Создание дерева структуры тегированного PDF/UA-2 на основе семантического содержимого
Краткий обзор
Заголовок раздела «Краткий обзор»Этот рецепт создаёт тегированный файл Portable Document Format/Universal Accessibility 2 (PDF/UA-2) с учётом стандарта International Organization for Standardization (ISO) 14289-2. NextPDF создаёт дерево логической структуры, последовательности маркированного содержимого, язык каталога и идентификационные метаданные на уровне документа. Эта структура поддерживает доступное представление, но решение о соответствии выносит независимое средство проверки. Рецепт соответствует examples/31-pdfua2-tagged.php.
Установка
Заголовок раздела «Установка»composer require nextpdf/core:^3Поместите средство проверки PDF/UA-2 в PATH для верификации. В этом рецепте используется veraPDF с профилем ua2. Для создания тегированной структуры пакет Pro или Enterprise не нужен.
Концептуальный обзор
Заголовок раздела «Концептуальный обзор»Тегированный PDF содержит параллельное дерево логической структуры наряду с потоком визуального содержимого. Вспомогательные технологии читают это дерево, а не пиксельный макет, поэтому именно структура задаёт внешний порядок чтения. ISO 14289-2 устанавливает для этого четыре требования. Реальное (не артефактное) содержимое должно быть достижимо через это дерево (§8.2.2). Элементы структуры должны быть вложены в определённом порядке (§8.2.3). Каждый элемент должен разрешаться в известное пространство имён структуры — напрямую или через сопоставление ролей (§8.2.4). Естественный язык содержимого объявляется на уровне документа и уточняется для каждого элемента структуры, где он отличается (§8.4.4).
NextPDF моделирует это через типизированный ConformanceMode. enableTaggedPdf() задаёт ConformanceMode::PdfUa2, что (a) заставляет конвейер Hypertext Markup Language (HTML) подключить TaggedContentEmitter при создании парсера, (b) устанавливает в каталоге флаг MarkInfoMarked, сигнализирующий о тегированном PDF (ISO 32000-2 §14.7), и (c) записывает языковой тег Best Current Practice 47 (BCP-47) в запись каталога Lang. Кроме того, модуль записи создаёт для каждой страницы запись Tabs, чтобы порядок обхода по табуляции следовал порядку структуры (ISO 32000-2 §14.8).
Строгие инварианты UA-2 применяются только к ConformanceMode::PdfUa2. По замыслу создание строгой ConformancePolicy для любого другого режима выбрасывает InvalidConfigException.
Поверхность API
Заголовок раздела «Поверхность API»Поверхность application programming interface (API) формируется по PHPDoc. Используйте следующие основные точки входа:
\NextPDF\Core\Document::createStandalone(): DocumentDocument::enableTaggedPdf(string $lang = 'en', ?ConformancePolicy $policy = null): staticDocument::setLanguage(string $lang): static\NextPDF\Conformance\ConformancePolicy::strictUa2(): self\NextPDF\Conformance\ConformanceMode::PdfUa2(режим, задаваемыйenableTaggedPdf())Document::beginTag(string $type): static/Document::endTag(): static(ручное тегирование для содержимого, отличного от HTML)
Пример кода — быстрый старт
Заголовок раздела «Пример кода — быстрый старт»<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
// Enable tagged mode BEFORE writeHtml(). The HTML pipeline detects the// mode at parser construction time and wires the tagged-content emitter.$doc->enableTaggedPdf(lang: 'en');
$doc->setTitle('Quarterly Accessibility Report');$doc->setLanguage('en');$doc->addPage();
$doc->writeHtml(<<<'HTML'<h1>Quarterly Accessibility Report</h1><p>This document opts into tagged PDF so assistive technology can exposea meaningful reading order.</p><ul> <li>Headings carry semantic roles.</li> <li>Lists keep their item structure.</li></ul>HTML);
$doc->save(__DIR__ . '/output/31-pdfua2-tagged.pdf');
echo "Created: output/31-pdfua2-tagged.pdf\n";Пример кода — продакшен
Заголовок раздела «Пример кода — продакшен»Эта самодостаточная программа может выполняться в тестовой среде. В продакшене лучше сразу завершаться с ошибкой при некорректном языковом теге, а не обнаруживать его только при запуске внешнего средства проверки. Передайте ConformancePolicy::strictUa2(), чтобы отклонить недопустимый тег BCP-47 на границе API, а затем поставьте сборку в зависимость от вердикта средства проверки.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Conformance\ConformancePolicy;use NextPDF\Core\Document;use NextPDF\Exception\InvalidConfigException;
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: (__DIR__ . '/accessible.pdf');
try { $doc = Document::createStandalone();
// Strict UA-2: a malformed BCP 47 tag throws here, not silently at // write time. strictUa2() also forces the §8.4.4 Lang validation. $doc->enableTaggedPdf(lang: 'en-GB', policy: ConformancePolicy::strictUa2());
$doc->setTitle('Accessible Annual Report 2026'); $doc->setLanguage('en-GB'); $doc->addPage();
$doc->writeHtml(<<<'HTML'<h1>Annual Report 2026</h1><p>Audited results for the financial year ending March 2026.</p><h2>Segment performance</h2><table> <tr><th>Segment</th><th>Revenue</th></tr> <tr><td>Cloud</td><td>42.1</td></tr> <tr><td>Services</td><td>18.7</td></tr></table>HTML);
$doc->save($out);} catch (InvalidConfigException $e) { fwrite(STDERR, "Tagged PDF/UA-2 setup rejected: {$e->getMessage()}\n"); exit(1);}
// The gate is the checker, not the library.$exitCode = 0;$report = [];exec('verapdf --flavour ua2 ' . escapeshellarg($out), $report, $exitCode);
if ($exitCode !== 0) { fwrite(STDERR, "veraPDF FAILED — output is not PDF/UA-2 conforming\n"); fwrite(STDERR, implode("\n", $report) . "\n"); exit(1);}
echo "veraPDF PASS — accessible.pdf carries a conforming UA-2 structure\n";На хосте, где verapdf --flavour ua2 сообщает о соответствии файла, ожидаемый стандартный вывод (STDOUT) выглядит так:
veraPDF PASS — accessible.pdf carries a conforming UA-2 structureЕсли enableTaggedPdf() отклоняет языковой тег, программа завершается с ненулевым кодом после Tagged PDF/UA-2 setup rejected: … в стандартном потоке ошибок (STDERR). Если средство проверки сообщает о проблеме, программа завершается с ненулевым кодом после veraPDF FAILED — output is not PDF/UA-2 conforming. Вердикт выносит средство проверки: NextPDF создаёт структуру, но не заявляет соответствие.
Граничные случаи и подводные камни
Заголовок раздела «Граничные случаи и подводные камни»- Порядок вызовов.
enableTaggedPdf()послеwriteHtml()не тегирует задним числом уже записанное содержимое. Сначала включайте режим тегирования. - Строгий контроль языка. Без политики некорректный тег BCP-47 молча отбрасывается и проявляется только на этапе проверки. С
ConformancePolicy::strictUa2()тот же тег выбрасываетInvalidConfigExceptionна границеenableTaggedPdf()(ISO 14289-2 §8.4.4, строгий путь). - Идемпотентное повторное включение. Если вызвать
enableTaggedPdf()дважды, NextPDF обновляет язык, не перестраивая уже заполненное дерево структуры. - Ручное тегирование. Для содержимого, отличного от HTML, оборачивайте элементы в
beginTag()/endTag(). Роли-контейнеры (Table,TR,L,LI) становятся группирующими элементами без маркированного содержимого. Листовые роли (P,H1–H6,TD) получают идентификаторы маркированного содержимого (MCID). - Взаимоисключение режимов. Строгая
ConformancePolicyдопустима только сConformanceMode::PdfUa2. Сочетание строгих флагов UA-2 с режимом PDF/A выбрасываетInvalidConfigException. Чтобы создать тегированный результат PDF/A, включайте режим тегирования и профиль PDF/A по отдельности.
Производительность
Заголовок раздела «Производительность»Дерево структуры добавляет одно параллельное дерево лёгких словарей и операторы BDC/EMC для каждого фрагмента текста. Для типичного отчёта эти накладные расходы составляют несколько процентов от размера вывода и остаются в пределах бюджета 2000 мс / 128 МБ. Применяется профиль семантической воспроизводимости, поскольку результат, ориентированный на средство проверки, сравнивается по структурному абстрактному синтаксическому дереву (AST) и метаданным, а не по сырым байтам. См. раздел “Соответствие”.
Замечания по безопасности
Заголовок раздела «Замечания по безопасности»Размещение данных и меры по защите персональных данных
Заголовок раздела «Размещение данных и меры по защите персональных данных»Дерево структуры содержит тот же текст, что и видимое содержимое. Если исходный HTML содержит персональные данные, включая персонально идентифицируемую информацию (PII), эти данные также доступны через дерево и через атрибуты ActualText/Alt. Применяйте то же редактирование и минимизацию перед оформлением, что и для видимого содержимого. Тегирование не добавляет нового канала утечки, но по замыслу делает текст программно извлекаемым.
Безопасная телеметрия и очистка журналов
Заголовок раздела «Безопасная телеметрия и очистка журналов»Рецепт выводит в STDOUT только фиксированную строку состояния. Он направляет PDF во внешний путь тестовой среды (NEXTPDF_COOKBOOK_OUTPUT) или по пути, заданному вызывающей стороной. Текст документа никогда не записывается в журнал. Держите вывод средства проверки, который может содержать фрагменты содержимого, вне общих журналов.
Модель угроз
Заголовок раздела «Модель угроз»Тегированный PDF не является границей доверия. Если ваш потребитель доверяет дереву структуры при автоматической обработке, он всё равно должен проверять файл, поскольку злоумышленный производитель может создать структурно корректное, но вводящее в заблуждение дерево. Рассматривайте структуру как средство обеспечения доступности, а не как сигнал целостности или подлинности.
Поведение в режиме FIPS
Заголовок раздела «Поведение в режиме FIPS»Этот рецепт не выполняет криптографических операций. Режим Federal Information Processing Standards (FIPS) не меняет его поведение. Подписание и шифрование не задействованы.
Соответствие PDF/UA-2
Заголовок раздела «Соответствие PDF/UA-2»| Требование PDF/UA-2 | Что создаёт NextPDF | Раздел |
|---|---|---|
| Реальное содержимое находится в дереве структуры | StructTreeRoot с StructElem для каждого блока и маркированным содержимым, связанным через MCID | ISO 14289-2 §8.2.2 |
| Определённое вложение и порядок чтения | Блочные элементы сопоставлены с grouping/leaf-ролями в порядке документа | ISO 14289-2 §8.2.3 |
| Известное пространство имён структуры | Роли в пространстве имён PDF 2.0; теги HTML сопоставлены с ролями там, где это нужно | ISO 14289-2 §8.2.4 |
| Язык документа и элемента | Каталог Lang из тега BCP-47; Lang для каждого элемента, где он отличается | ISO 14289-2 §8.4.4 |
| Нетекстовое содержимое имеет текстовую альтернативу | Alt/ActualText на элементах структуры figure/non-text | ISO 14289-2 §8.5.1 |
| Связи таблицы | Table/TR/TH/TD-роли со связью заголовков | ISO 14289-2 §8.2.5.26 |
| Метаданные идентификации части | Идентификация на уровне документа, запланированная при сохранении | ISO 14289-2 §Введение (pdfua2#p17) |
Сопоставление тегов с ISO 32000-2 §14
Заголовок раздела «Сопоставление тегов с ISO 32000-2 §14»PDF/UA-2 надстраивает требования доступности над механизмом тегированного PDF из ISO 32000-2. NextPDF опирается на это сопоставление:
| Что эмитирует NextPDF | Механизм ISO 32000-2 §14 | Раздел |
|---|---|---|
Дерево логической структуры (StructTreeRoot) | Логическая структура тегированного PDF | §14.7 (iso32000_2_sec14#x1.x38.p13) |
Каталог MarkInfo << /Marked true >> | Маркер тегированного PDF | §14.7 (iso32000_2_sec14#x1.x40.p3) |
Запись Tabs для каждой страницы, которая следует порядку структуры | Структурная навигация / порядок табуляции | §14.8 (iso32000_2_sec14#x1.x50) |
Сопоставление с WCAG 2.2
Заголовок раздела «Сопоставление с WCAG 2.2»PDF/UA-2 выражает в формате PDF требования к структуре, которые Web Content Accessibility Guidelines (WCAG) 2.2 формулирует независимо от формата. Соответствующее сопоставление:
| Критерий успеха WCAG 2.2 | Механизм PDF/UA-2, который создаёт этот рецепт |
|---|---|
| 1.3.1 Информация и взаимосвязи (уровень A) | Дерево структуры делает заголовки, списки и связи таблиц программно определяемыми (wcag_2_2#x2.x3.x3.x1.p3). |
| 1.3.2 Осмысленная последовательность (уровень A) | Порядок структуры определяет порядок чтения независимо от визуального макета. |
| 3.1.1 Язык страницы (уровень A) | Запись каталога Lang из тега BCP-47. |
| 1.1.1 Нетекстовое содержимое (уровень A) | Alt/ActualText на нетекстовых элементах структуры (ISO 14289-2 §8.5.1). |
Это сопоставление показывает, какие критерии WCAG 2.2 поддерживает созданная структура. Оно не является заявлением о соответствии WCAG. Соответствие WCAG охватывает весь пользовательский опыт, и его определяет оценка доступности, а не производитель.
Соответствие
Заголовок раздела «Соответствие»| Утверждение | Стандарт | Раздел | reference_id (идентификатор ссылки) |
|---|---|---|---|
| Реальное содержимое требует логической структуры. | ISO 14289-2 | §8.2.2 | |
| Элементы структуры следуют определённому вложению и порядку чтения. | ISO 14289-2 | §8.2.3 | |
| Каждый элемент структуры разрешается в известное пространство имён — напрямую или через сопоставление ролей. | ISO 14289-2 | §8.2.4 | |
| Естественный язык объявляется на уровне документа и элемента структуры. | ISO 14289-2 | §8.4.4 | |
| Нетекстовое содержимое несёт текстовую альтернативу. | ISO 14289-2 | §8.5.1 | |
| Ячейки таблицы содержат связи row/header/data. | ISO 14289-2 | §8.2.5.26 | |
Маркером тегированного PDF является флаг каталога MarkInfoMarked. | ISO 32000-2 | §14.7 | |
| Соответствие определяется по части стандарта, а не утверждается производителем. | ISO 14289-2 | §8.14.2 |
NextPDF создаёт тегированную структуру, которая поддерживает доступное представление. Поддержка — это не соответствие. Этот рецепт не заявляет соответствие PDF/UA-2. Его определяет независимое средство проверки, например veraPDF. Запускайте средство проверки, прежде чем заявлять, что файл соответствует.