HTML转PDF时修复iText生成PDF的注释缺失替代描述无障碍问题
我之前在做HTML转PDF的无障碍适配时,也被PAC3的这个“注释缺失替代描述”问题卡过一阵——本质就是PDF里的链接没有可访问性名称,导致屏幕阅读器无法正确解读。结合iText的使用经验,给你分享两个靠谱的解决方案:
方案1:在HTML中预先定义链接的无障碍文本
最省心的方式是从源头解决,在HTML里给链接加上aria-label属性(优先推荐)或者title属性,iText的pdfHTML插件(iText 7+)会自动把这些属性映射到PDF标签树的链接替代文本里,PAC3检测就能直接识别。
举个例子:
如果是普通文本链接,原来的写法可能是:
<a href="https://example.com">点击这里</a>
改成带无障碍描述的版本:
<a href="https://example.com" aria-label="访问示例官网获取产品文档">点击这里</a>
如果是纯图标链接(没有可见文本),要同时给图标和链接加描述:
<a href="annual-report.pdf" aria-label="下载2024年度业绩报告PDF"> <img src="download-icon.png" alt="下载图标"> </a>
提示:一定要用iText 7及以上版本的pdfHTML,旧版iText对无障碍属性的支持基本等于没有。
方案2:用iText API在转换后补全链接的替代文本
如果没法修改原始HTML,那就只能在生成PDF后,手动遍历结构树给链接加/Alt属性(这就是你手动在标签树里操作的代码版)。
下面是iText 7的示例代码:
// 假设已经通过HtmlConverter生成了PdfDocument对象 PdfDocument pdfDoc = new PdfDocument(new PdfWriter("output.pdf")); pdfDoc.setTagged(); // 必须开启标签化,否则没有结构树 ConverterProperties props = new ConverterProperties(); props.setTaggingEnabled(true); HtmlConverter.convertToPdf(new FileInputStream("input.html"), pdfDoc, props); // 遍历结构树,给链接添加替代文本 fixLinkAccessibility(pdfDoc.getStructTreeRoot()); pdfDoc.close(); // 递归遍历结构树的方法 private static void fixLinkAccessibility(PdfStructElem elem) { // 判断当前元素是否是链接类型 if (PdfName.Link.equals(elem.getRole())) { // 这里可以根据链接的URL或内容自定义替代文本 String altText = generateLinkAltText(elem); if (altText != null && !altText.isBlank()) { elem.put(PdfName.Alt, new PdfString(altText)); } } // 递归处理子元素 for (PdfStructElem child : elem.getKids()) { fixLinkAccessibility(child); } } // 自定义生成替代文本的逻辑,比如根据URL生成 private static String generateLinkAltText(PdfStructElem linkElem) { // 获取链接的URI(这里的逻辑需要根据你的PDF结构调整,可能需要适配不同的注释存储方式) PdfDictionary annotDict = getLinkAnnotation(linkElem); if (annotDict != null) { PdfString uri = annotDict.getAsDict(PdfName.A).getAsString(PdfName.URI); if (uri != null) { return "跳转至:" + uri.toUnicodeString(); } } // 默认文本 return "外部链接"; } // 辅助方法:从结构元素获取对应的链接注释 private static PdfDictionary getLinkAnnotation(PdfStructElem linkElem) { PdfObject obj = linkElem.getRef(); if (obj instanceof PdfIndirectReference) { PdfDictionary dict = ((PdfIndirectReference) obj).getRefersTo().getAsDictionary(); if (PdfName.Link.equals(dict.getAsName(PdfName.Subtype))) { return dict; } } return null; }
注意:这段代码的核心是给链接结构元素添加/Alt属性,PAC3检测时会读取这个属性作为链接的替代描述。另外,一定要确保生成的PDF是Tagged PDF(也就是代码里的pdfDoc.setTagged()和props.setTaggingEnabled(true)必须开启),否则结构树不存在,没法修改。
关键注意事项
- 必须使用iText 7+的pdfHTML插件,旧版iText对无障碍标签的支持非常有限;
- 转换时一定要开启标签化,否则PDF没有结构树,PAC3也没法检测无障碍属性;
- 优先用方案1,从HTML层面解决比事后修改PDF要高效得多,也不容易出错。
内容的提问来源于stack exchange,提问作者Charles Stockman
相关产品推荐
相关产品推荐

