如何自动或批量修复 PDF,以满足 WCAG 2.0 无障碍要求?
可以用编程和现成工具批量修复部分 PDF 无障碍问题。但对于来源复杂的 100,000+ 份文件,仅凭自动处理完成或检测通过,还不能认定全部符合 WCAG 2.0。建议先将文件分类,自动处理规则明确的问题,再由人工检查内容语义和实际操作。
Author 可以批量补充,但 WCAG 2.0 并未要求所有 PDF 都填写作者。作者字段通常也不是最影响使用的问题,应优先处理文档标题、语言、可读取的文本、标签结构和阅读顺序。
先明确验收要求和自动化边界
“符合 WCAG 2.0”需要明确到具体等级,例如 Level AA。以 AA 为目标,就要满足所有适用的 A 级和 AA 级成功准则。验收时应逐项核对具体要求,不能只看检测工具是否全部显示绿色。参见 WCAG 2.0 的符合性要求。
PDF/UA 可以作为 PDF 结构方面的技术目标,但它与 WCAG 的检查范围不同,两者不能直接互换。PDF/UA 主要规定 PDF 如何支持辅助技术;验收时还需要检查内容是否清楚、替代文本是否准确等问题。参见 PDF/UA Foundation 的 PAC 指南。
| 问题 | 可以自动处理的部分 | 仍需判断的内容 |
|---|---|---|
| 缺少标题 | 从可信业务数据写入标题 | 标题是否描述文档主题或用途 |
| 缺少默认语言 | 按已确认的语言设置 /Lang | 多语言段落是否需要单独标记 |
| 扫描件没有文本 | 使用 OCR 添加文本层 | 识别结果是否准确 |
| 缺少结构标签 | 自动识别并生成初步标签 | 标题层级、表格结构、阅读顺序是否正确 |
| 图片缺少替代文本 | 检测缺失情况,生成待审核草稿 | 描述是否传达图片在当前语境中的信息 |
| 表单无障碍问题 | 检测部分字段属性 | 字段名称、键盘操作和错误提示是否可用 |
给 PDF 设置 /MarkInfo /Marked true,或创建一个空的 /StructTreeRoot,都不会自动生成正确的标签结构。OCR 也只解决文本识别问题,不会完成标题、列表、表格等语义标记。
大规模修复应如何安排
1. 建立清单,按来源和模板分类
清单至少要记录文件位置、哈希、页数、来源系统、是否有源文件,以及文本层、标签、表单、加密和数字签名等情况。
先区分以下几类:
- 有 Word、InDesign 等可编辑源文件的文档;
- 由同一业务系统、同一模板生成的文档;
- 来源不统一、版式复杂的历史文件;
- 扫描件。
有源文件时,通常应先修复源文件或生成模板,再重新导出带标签的 PDF。对于同一模板生成的数万份文件,值得开发专门的处理规则;零散的历史文件往往需要更多人工修复。
2. 按用户需求确定处理顺序
优先处理仍在使用的重要文档,例如申请表、操作说明,以及访问量高或用户已提出无障碍需求的文件。旧文件是否删除、替换或归档,由内容负责人根据组织要求决定。
资源有限时可以分批交付,但列入排期的文件仍需修复才能满足要求。对尚未修复、又有使用需求的文件,应提供可访问版本或其他获取方式。
3. 用代表性样本试跑
选择能覆盖不同语言、模板、扫描质量、表格和表单的样本,比较候选工具处理前后的结果。
评估时记录每份文件的处理费用、人工复核时间、失败原因和返工情况。生成的标签数量不足以衡量工具节省了多少修复时间。
哪些工具值得评估
| 工具 | 适合的用途 | 使用边界 |
|---|---|---|
| Adobe Acrobat Pro | 自动打标、检查,以及逐份修复阅读顺序和结构 | 报告中仍有需要人工检查的项目 |
| Adobe PDF Accessibility Auto-Tag API | 将自动打标接入批处理工作流 | 自动打标只是修复过程的一部分,输出需要复核 |
| axesFlip | 通过模板处理重复版式,提供 CLI 和 REST Server | 是否适合现有文档,需要用实际样本验证 |
| pikepdf | 按明确规则批量修改元数据、PDF 字典等内容 | 不负责自动理解文档语义 |
| OCRmyPDF | 为扫描件添加可搜索文本层 | OCR 后仍需修复结构、检查识别结果 |
| PAC、veraPDF | 检查和验证,辅助人工复核或接入自动流程 | 检测工具不会完成内容修复;veraPDF 的 PDF/UA 验证限于机器可检查的要求 |
采购或接入前,还要确认授权方式、文件及页数限制、并发配额、中文识别效果,以及文档是否允许上传到云服务。批量处理能力和最终修复质量都需要单独验证。
代码示例:按审核清单更新标题、作者和语言
可以先从文档管理系统取得可靠数据,批量写入 PDF。标题应使用经过确认的信息,不要一律填成文件名;作者未知时,也不要统一填组织名称。
W3C 的 PDF18 技术说明了文档标题及 DisplayDocTitle 的设置;PDF16 技术说明了默认语言 /Lang 的设置。
以下是使用 pikepdf 的最小批处理示例。运行前,清单应已审核,输入文件应未加密、未签名,并且允许重新保存。代码会按清单更新已有值,将结果写入独立目录。
安装依赖:
python -m pip install pikepdf
准备 manifest.json。author 为可选字段,未知时省略:
[
{
"path": "guides/application-guide.pdf",
"title": "申请办理指南",
"language": "zh-CN",
"author": "业务服务部门"
}
]
将清单中的 PDF 放在 pdf-in/ 下,然后运行:
import json
from pathlib import Path
import pikepdf
source_root = Path("pdf-in").resolve()
output_root = Path("pdf-out").resolve()
items = json.loads(
Path("manifest.json").read_text(encoding="utf-8")
)
for item in items:
try:
source = (source_root / item["path"]).resolve()
relative = source.relative_to(source_root)
target = output_root / relative
if target.exists():
raise FileExistsError(target)
with pikepdf.Pdf.open(source) as pdf:
if pdf.is_encrypted:
raise ValueError("Encrypted PDF requires separate handling")
with pdf.open_metadata() as metadata:
metadata["dc:title"] = item["title"]
if item.get("author"):
metadata["dc:creator"] = [item["author"]]
pdf.Root["/Lang"] = item["language"]
preferences = pdf.Root.get("/ViewerPreferences")
if preferences is None:
preferences = pikepdf.Dictionary()
pdf.Root["/ViewerPreferences"] = preferences
preferences["/DisplayDocTitle"] = True
target.parent.mkdir(parents=True, exist_ok=True)
pdf.save(target)
result = {"path": item["path"], "status": "metadata_updated"}
except Exception as exc:
result = {
"path": item.get("path"),
"status": "failed",
"error": str(exc),
}
print(json.dumps(result, ensure_ascii=False))
open_metadata() 会协调更新 XMP 和旧式 Document Info 中对应的常用字段,具体行为见 pikepdf 元数据文档。
这段代码只更新元数据,不生成标签,也不修复阅读顺序。默认语言描述的是文档的主要语言,其他语言的段落可能仍需单独标记。
批处理后如何验收
每个批次都应重新运行自动检查,并由人工复核工具无法可靠判断的问题,包括:
- 标题、段落、列表和表格是否按合理顺序读取;
- 表头是否与对应数据正确关联;
- 图片替代文本是否准确,装饰内容是否恰当处理;
- 链接和表单能否通过键盘操作;
- OCR 是否误识别了数字、符号或关键文字;
- 对比度及依赖颜色传递的信息是否符合目标要求。
还要使用选定的 PDF 阅读器和屏幕阅读器组合实际操作。Acrobat 将检查结果分为自动通过、失败和 Needs Manual Check,其中 Needs Manual Check 必须人工验证。参见 Adobe 的检查说明。
对于稳定模板,可以安排分层抽样和回归检查,但抽样通过不能证明每份文件都合规。独有版式、复杂表格、交互表单和异常输出都需要明确安排复核。
批量修改时的注意事项
保留原文件、输入哈希、工具版本、修改记录和检查报告,方便重试失败任务、追溯处理结果。数字签名文件应单独处理,重新保存可能使签名失效;加密文件也需要先确认处理权限和输出策略。
不要对所有文件强制重新 OCR 或重新打标,这可能破坏已有结构。OCRmyPDF 的相关文档也说明了部分处理方式对标签结构的影响。
如果采用敏捷方式推进,可以将“已完成”的条件定为:指定问题已修复,自动检查已重新运行,所需的人工复核已完成,并已保存验收记录。同时修正文档生成流程,避免历史文件尚未处理完,新的无障碍问题又不断进入库中。
备注:内容仅供参考。
