无障碍 PDF
无障碍 PDF(又称 Tagged PDF)是一种具备结构标记的 PDF 文件,让视障或其他身心障碍用户能够通过屏幕阅读器等辅助技术理解文件内容。TCPDF-Next 支持创建符合 PDF/UA (ISO 14289) 标准的无障碍文件。
什么是无障碍 PDF?
一份合格的无障碍 PDF 必须包含以下要素:
- 结构标记(Structure Tree) -- 用语义标签(标题、段落、表格、图片)构建文件的逻辑结构树
- 替代文字(Alt Text) -- 为所有非文字内容(图片、图表)提供文字描述
- 语言标记 -- 标记文件语言与内容语言
- 阅读顺序 -- 定义与视觉排版无关的逻辑阅读顺序
- 表格结构 -- 表格需有正确的表头与数据单元格标记
- 书签导航 -- 长文件需提供书签供导航使用
- 色彩对比 -- 文字与背景的对比度需符合 WCAG 标准
- 字体信息 -- 字体需有 Unicode 对应表(ToUnicode CMap)以支持文字提取
相关标准
| 标准 | 范围 |
|---|---|
| PDF/UA-2 (ISO 14289-2:2024) | PDF 通用无障碍标准 |
| WCAG 2.1 (W3C) | 网页内容无障碍指引 |
| Section 508(美国) | 美国联邦无障碍要求 |
| EN 301 549(欧盟) | 欧盟无障碍要求 |
| PDF 2.0 Annex L (ISO 32000-2) | Tagged PDF 技术规格 |
基本无障碍 PDF
文件设置
php
use YeeeFang\TcpdfNext\Document\PdfDocument;
use YeeeFang\TcpdfNext\Document\PageFormat;
use YeeeFang\TcpdfNext\Accessibility\TagManager;
$pdf = PdfDocument::create()
->setPageFormat(PageFormat::A4)
->setTitle('无障碍文件示例')
->setAuthor('TCPDF-Next')
->setLanguage('zh-CN') // 设置文件语言
->setTagged(true) // 启用标记式 PDF
->setDisplayDocTitle(true) // 阅读器标题栏显示文件标题而非文件名
->build();
$tag = $pdf->getTagManager();
$page = $pdf->addPage();标题标记
标题必须按照层级顺序使用,不可跳级(例如不能从 H1 直接跳到 H3):
php
use YeeeFang\TcpdfNext\Content\FontStyle;
// H1 标题
$tag->beginTag('H1');
$page->addText('年度报告 2026')
->setPosition(20, 25)
->setFont('Helvetica', size: 24, style: FontStyle::BOLD);
$tag->endTag();
// H2 标题
$tag->beginTag('H2');
$page->addText('执行摘要')
->setPosition(20, 50)
->setFont('Helvetica', size: 18, style: FontStyle::BOLD);
$tag->endTag();
// H3 标题
$tag->beginTag('H3');
$page->addText('财务亮点')
->setPosition(20, 75)
->setFont('Helvetica', size: 14, style: FontStyle::BOLD);
$tag->endTag();标题层级
屏幕阅读器会根据标题层级构建文件大纲供用户导航。跳过层级会让用户无法正确理解文件结构。
段落标记
php
$tag->beginTag('P');
$page->addParagraph(
'公司在 2026 年交出亮眼成绩,营收较去年增长 15%,'
. '达到 24 亿元。营业利润率提升了 200 个基点,'
. '反映出我们在运营效率上的持续改善。'
)
->setPosition(20, 95)
->setWidth(170)
->setFont('Times', size: 12)
->setLineHeight(1.5);
$tag->endTag();图片替代文字
图片分为两类:信息性图片需要替代文字,装饰性图片则标记为 Artifact 让屏幕阅读器跳过:
php
use YeeeFang\TcpdfNext\Graphics\Color;
// 信息性图片:需要描述性替代文字
$tag->beginTag('Figure');
$page->addImage('/assets/revenue-chart.png')
->setPosition(20, 130)
->setSize(170, 80)
->setAltText('柱状图显示公司 2022 至 2026 年营收,从 15 亿元稳定增长至 24 亿元');
$tag->beginTag('Caption');
$page->addText('图一:2022-2026 年营收趋势(单位:亿元)')
->setPosition(20, 212)
->setFont('Helvetica', size: 9)
->setColor(Color::rgb(100, 100, 100));
$tag->endTag(); // Caption
$tag->endTag(); // Figure
// 装饰性图片:标记为 Artifact,屏幕阅读器会忽略
$page->addImage('/assets/decorative-line.png')
->setPosition(20, 220)
->setSize(170, 2)
->setArtifact(true);替代文字撰写要点
- 信息性图片:描述图片传达的信息,而非图片的外观。例如图表要说明趋势与数据,而非「一张柱状图」
- 装饰性图片:标记为 Artifact,不需要替代文字
- 复杂图表:在替代文字中提供摘要,并在正文中补充详细说明
表格结构
表格需要正确的表头标记,屏幕阅读器才能将数据单元格与对应的列标题关联起来:
php
$tag->beginTag('Table');
// 表格标题
$tag->beginTag('Caption');
$page->addText('表一:季度营收一览表(单位:万元)')
->setFont('Helvetica', size: 10, style: FontStyle::BOLD);
$tag->endTag();
// 表头行
$tag->beginTag('TR');
$headers = ['季度', '营收', '增长率', '利润率'];
foreach ($headers as $header) {
$tag->beginTag('TH', attributes: ['scope' => 'col']);
$page->addText($header)
->setFont('Helvetica', size: 10, style: FontStyle::BOLD);
$tag->endTag();
}
$tag->endTag(); // TR
// 数据行
$rows = [
['第一季', '5,480', '+12%', '21%'],
['第二季', '5,920', '+14%', '22%'],
['第三季', '6,180', '+16%', '23%'],
['第四季', '6,420', '+18%', '22%'],
];
foreach ($rows as $row) {
$tag->beginTag('TR');
foreach ($row as $i => $cell) {
if ($i === 0) {
$tag->beginTag('TH', attributes: ['scope' => 'row']);
} else {
$tag->beginTag('TD');
}
$page->addText($cell)->setFont('Times', size: 10);
$tag->endTag();
}
$tag->endTag(); // TR
}
$tag->endTag(); // TableArtifact 标记
页眉、页脚、页码、水印等不属于文件逻辑内容的元素,应标记为 Artifact:
php
use YeeeFang\TcpdfNext\Content\Alignment;
$pdf->onPageFooter(function (Page $page, int $pageNumber, int $totalPages) use ($tag) {
$tag->beginArtifact('Pagination');
$page->addText("第 {$pageNumber} 页,共 {$totalPages} 页")
->setPosition(105, 285)
->setFont('Helvetica', size: 8)
->setAlignment(Alignment::CENTER);
$tag->endArtifact();
});使用 HTML 自动生成标记
TCPDF-Next 的 HTML 渲染器可以从语义化 HTML 自动生成对应的 PDF 结构标记,大幅简化无障碍文件的创建流程:
php
use YeeeFang\TcpdfNext\Html\HtmlRenderer;
$pdf = PdfDocument::create()
->setTagged(true)
->setLanguage('zh-CN')
->build();
$renderer = new HtmlRenderer($pdf);
$renderer->setAutoTagging(true);
$html = <<<'HTML'
<h1>年度报告 2026</h1>
<h2>执行摘要</h2>
<p>公司在 2026 年交出亮眼成绩,营收较去年增长 15%。</p>
<figure>
<img src="/assets/chart.png" alt="营收增长折线图,显示每季稳定攀升" width="200" />
<figcaption>图一:2022-2026 年营收趋势</figcaption>
</figure>
<h2>财务数据</h2>
<table>
<caption>季度营收</caption>
<thead>
<tr>
<th scope="col">季度</th>
<th scope="col">营收(万元)</th>
</tr>
</thead>
<tbody>
<tr><td>第一季</td><td>5,480</td></tr>
<tr><td>第二季</td><td>5,920</td></tr>
<tr><td>第三季</td><td>6,180</td></tr>
<tr><td>第四季</td><td>6,420</td></tr>
</tbody>
</table>
<ul>
<li>客户满意度:92%</li>
<li>员工留任率:88%</li>
</ul>
HTML;
$renderer->writeHtml($html);自动标记器会将 HTML 元素对应到 PDF 结构类型:
| HTML 元素 | PDF 结构类型 |
|---|---|
<h1> - <h6> | H1 - H6 |
<p> | P |
<table> | Table |
<th> | TH |
<td> | TD |
<ul>, <ol> | L |
<li> | LI |
<figure> | Figure |
<figcaption> | Caption |
<img> (含 alt) | Figure + Alt Text |
<a> | Link |
<blockquote> | BlockQuote |
内置无障碍检查器
在输出前使用内置检查器验证无障碍合规性:
php
use YeeeFang\TcpdfNext\Accessibility\AccessibilityChecker;
$checker = new AccessibilityChecker($pdf);
$result = $checker->validate();
if (!$result->isAccessible()) {
foreach ($result->getIssues() as $issue) {
echo sprintf(
"[%s] %s -- %s (WCAG %s)\n",
$issue->getSeverity()->name,
$issue->getElement(),
$issue->getMessage(),
$issue->getWcagCriterion()
);
}
}
// 输出示例:
// [ERROR] 第 3 页图片 -- 缺少替代文字 (WCAG 1.1.1)
// [WARNING] 第 5 页表格 -- 缺少表头标记 (WCAG 1.3.1)外部验证工具
使用 PAC (PDF Accessibility Checker) 进行完整的 PDF/UA 验证。PAC 是免费的 Windows 应用程序,会根据 ISO 14289 标准执行 107 项检查。
无障碍检查清单
在发布文件前,请确认以下项目:
- [ ] 设置了文件标题(
setTitle()) - [ ] 启用标题栏显示文件标题(
setDisplayDocTitle(true)) - [ ] 设置了文件语言(
setLanguage('zh-CN')) - [ ] 所有内容都有结构标记
- [ ] 标题层级依序使用,没有跳级
- [ ] 所有信息性图片都有替代文字
- [ ] 装饰性元素标记为 Artifact
- [ ] 表格有正确的表头(
TH)与scope属性 - [ ] 阅读顺序符合逻辑
- [ ] 链接文字具有描述性
- [ ] 文字对比度至少 4.5:1(一般文字)或 3:1(大型文字)
- [ ] 字体包含 Unicode 对应表
- [ ] 超过 5 页的文件有书签导航
延伸阅读
- PDF/A-4 归档 -- 结合归档与无障碍需求
- HTML 转 PDF -- HTML 渲染与自动标记
- 表格 -- 表格排版基础