Ir al contenido

Emitir un árbol de estructura etiquetado para PDF/UA-2 a partir de contenido semántico

Esta receta crea un PDF etiquetado orientado a ISO 14289-2 (PDF/UA-2). NextPDF emite un árbol de estructura lógica, secuencias de contenido marcado, el idioma del catálogo y los metadatos de identificación a nivel de documento. Esa estructura facilita la autoría accesible, pero la conformidad la decide un verificador independiente. La receta sigue examples/31-pdfua2-tagged.php.

Ventana de terminal
composer require nextpdf/core:^3

El paso de verificación requiere que haya un verificador de PDF/UA-2 en PATH. Los ejemplos de esta receta usan veraPDF con el perfil ua2. No se necesita ningún paquete Pro ni Enterprise para emitir la estructura etiquetada.

Un PDF etiquetado incluye un árbol de estructura lógica paralelo al flujo de contenido visual. Las tecnologías de asistencia leen el árbol, no la disposición de los píxeles, por lo que la estructura determina el orden de lectura expuesto. ISO 14289-2 establece cuatro requisitos sobre este punto. El contenido real (que no sea artefacto) debe ser alcanzable a través de ese árbol (§8.2.2). Los elementos de estructura deben anidarse en un orden definido (§8.2.3). Cada elemento debe resolverse a un espacio de nombres de estructura conocido, directamente o mediante asignación de roles (§8.2.4). Además, el idioma natural del contenido se declara a nivel de documento y se refina por elemento de estructura cuando difiere (§8.4.4).

NextPDF modela esto con un ConformanceMode tipado. enableTaggedPdf() establece ConformanceMode::PdfUa2, lo que (a) hace que la pipeline HTML conecte un TaggedContentEmitter al construir el analizador, (b) activa la marca MarkInfoMarked del catálogo que señala un PDF etiquetado (ISO 32000-2 §14.7), y (c) registra el idioma BCP-47 para la entrada Lang del catálogo. El escritor también emite la entrada Tabs por página para que el orden de tabulación siga el orden de la estructura (ISO 32000-2 §14.8).

Las invariantes estrictas de UA-2 solo se aplican a ConformanceMode::PdfUa2. Construir una ConformancePolicy estricta para cualquier otro modo lanza InvalidConfigException por diseño.

La superficie de la API se genera a partir de PHPDoc. Los puntos de entrada principales:

  • \NextPDF\Core\Document::createStandalone(): Document
  • Document::enableTaggedPdf(string $lang = 'en', ?ConformancePolicy $policy = null): static
  • Document::setLanguage(string $lang): static
  • \NextPDF\Conformance\ConformancePolicy::strictUa2(): self
  • \NextPDF\Conformance\ConformanceMode::PdfUa2 (el modo que establece enableTaggedPdf())
  • Document::beginTag(string $type): static / Document::endTag(): static (etiquetado manual para contenido que no es HTML)
examples/31-pdfua2-tagged.php
<?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 expose
a 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";

Este es el programa autónomo y ejecutable mediante el harness. En producción, el código llamador falla rápido ante una etiqueta de idioma mal formada, en lugar de descubrirla solo al ejecutar el verificador externo. Pasar ConformancePolicy::strictUa2() permite rechazar una etiqueta BCP-47 no válida en el límite de la API; después, la compilación queda condicionada al veredicto del verificador.

<?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";

STDOUT esperado en un host cuyo verapdf --flavour ua2 informa que el archivo es conforme:

veraPDF PASS — accessible.pdf carries a conforming UA-2 structure

Si enableTaggedPdf() rechaza la etiqueta de idioma, el programa termina con código distinto de cero después de Tagged PDF/UA-2 setup rejected: … en STDERR. Si el verificador informa un problema, termina con código distinto de cero después de veraPDF FAILED — output is not PDF/UA-2 conforming. El veredicto corresponde al verificador: NextPDF emite la estructura, pero no afirma la conformidad.

  • Orden de las llamadas. enableTaggedPdf() después de writeHtml() no etiqueta retroactivamente el contenido ya escrito. Primero debe activarse el modo etiquetado.
  • Control estricto del idioma. Sin una política, una etiqueta BCP-47 no analizable se descarta de forma silenciosa y solo aparece al ejecutar el verificador. Con ConformancePolicy::strictUa2() la misma etiqueta lanza InvalidConfigException en el límite de enableTaggedPdf() (ISO 14289-2 §8.4.4 ruta estricta).
  • Reactivación idempotente. Llamar a enableTaggedPdf() dos veces actualiza el idioma sin reconstruir un árbol de estructura ya poblado.
  • Etiquetado manual. Para contenido que no es HTML, envuelve los elementos con beginTag() / endTag(). Los roles de contenedor (Table, TR, L, LI) se convierten en elementos de agrupación sin contenido marcado. Los roles hoja (P, H1H6, TD) obtienen MCID.
  • Exclusividad de modo. Una ConformancePolicy estricta solo es válida con ConformanceMode::PdfUa2. Combinar marcas estrictas de UA-2 con un modo PDF/A lanza InvalidConfigException. Para componer un entregable PDF/A etiquetado, activar por separado el modo etiquetado y el perfil PDF/A.

El árbol de estructura añade un árbol paralelo de diccionarios ligeros, más operadores BDC/EMC por tramo de texto. Para un informe típico, la sobrecarga representa un pequeño porcentaje del tamaño de salida y se mantiene cómodamente dentro del presupuesto de 2000 ms / 128 MB. El perfil de reproducibilidad semántica se aplica aquí porque un entregable orientado al verificador se compara por su árbol de sintaxis abstracta (AST) estructural y sus metadatos, no por los bytes en bruto. Ver la sección Conformidad.

El árbol de estructura contiene el mismo texto que el contenido visible. Si el HTML de origen contiene datos personales, esos datos también son alcanzables a través del árbol y de los atributos ActualText/Alt. Aplicar el mismo enmascaramiento y la misma minimización antes de generar el documento que se aplicarían al contenido visible. El etiquetado no añade ninguna nueva vía de exfiltración, pero sí hace que el texto sea extraíble programáticamente por diseño.

Telemetría segura y depuración de registros

Sección titulada «Telemetría segura y depuración de registros»

La receta escribe en STDOUT solo una línea de progreso fija. Enrutar el PDF al canal lateral del harness (NEXTPDF_COOKBOOK_OUTPUT) o a una ruta del llamador. El texto del documento nunca se registra. Mantener la salida del verificador, que puede reproducir fragmentos de contenido, fuera de los registros compartidos.

Un PDF etiquetado no es un límite de confianza. Un consumidor que confía en el árbol de estructura para el procesamiento automatizado aún debe validar el archivo, porque un productor hostil puede emitir un árbol estructuralmente bien formado pero engañoso. Tratar la estructura como una función de accesibilidad, no como una señal de integridad o autenticidad.

Esta recipe no realiza ninguna operación criptográfica. El modo FIPS no cambia su comportamiento. No interviene ninguna firma ni cifrado.

Requisito de PDF/UA-2Lo que emite NextPDFCláusula
El contenido real está en el árbol de estructuraStructTreeRoot con StructElem por bloque y contenido marcado enlazado por MCIDISO 14289-2 §8.2.2
Anidamiento y orden de lectura definidosElementos de bloque asignados a roles de grouping/leaf en orden de documentoISO 14289-2 §8.2.3
Espacio de nombres de estructura conocidoRoles en el espacio de nombres de PDF 2.0; etiquetas HTML con asignación de roles donde es necesarioISO 14289-2 §8.2.4
Idioma del documento y del elementoEl Lang del catálogo a partir de la etiqueta BCP-47; el Lang por elemento cuando difiereISO 14289-2 §8.4.4
El contenido que no es texto tiene una alternativa textualAlt/ActualText en los elementos de estructura figure/non-textISO 14289-2 §8.5.1
Relaciones de tablaTable/TR/TH/TD roles con asociación de encabezadosISO 14289-2 §8.2.5.26
Metadatos de identificación de parteIdentificación a nivel de documento programada al guardarISO 14289-2 §Intro (pdfua2#p17)

Referencia cruzada de etiqueta → ISO 32000-2 §14

Sección titulada «Referencia cruzada de etiqueta → ISO 32000-2 §14»

PDF/UA-2 superpone requisitos de accesibilidad sobre los mecanismos de PDF etiquetado de ISO 32000-2. La asignación en la que se basa NextPDF:

Emisión de NextPDFRecurso de ISO 32000-2 §14Cláusula
Árbol de estructura lógica (StructTreeRoot)Estructura lógica de PDF etiquetado§14.7 (iso32000_2_sec14#x1.x38.p13)
Catálogo MarkInfo << /Marked true >>Marcador de PDF etiquetado§14.7 (iso32000_2_sec14#x1.x40.p3)
Entrada Tabs por página que sigue el orden de la estructuraNavegación estructural / orden de tabulación§14.8 (iso32000_2_sec14#x1.x50)

PDF/UA-2 es la expresión en formato PDF de requisitos de estructura que WCAG 2.2 enuncia de forma independiente del formato. La correspondencia relevante:

Criterio de éxito de WCAG 2.2Mecanismo de PDF/UA-2 que produce esta recipe
1.3.1 Información y relaciones (Nivel A)El árbol de estructura hace que los encabezados, las listas y las relaciones de tabla sean programáticamente determinables (wcag_2_2#x2.x3.x3.x1.p3).
1.3.2 Secuencia significativa (Nivel A)El orden de la estructura define el orden de lectura con independencia de la disposición visual.
3.1.1 Idioma de la página (Nivel A)La entrada Lang del catálogo a partir de la etiqueta BCP-47.
1.1.1 Contenido que no es texto (Nivel A)Alt/ActualText en los elementos de estructura que no son texto (ISO 14289-2 §8.5.1).

Esta asignación muestra dónde la estructura emitida facilita un criterio de WCAG 2.2. No es una declaración de conformidad con WCAG. La conformidad con WCAG cubre toda la experiencia de usuario y la determina una evaluación de accesibilidad, no el productor.

DeclaraciónEspecificaciónCláusulareference_id
El contenido real requiere una estructura lógica.ISO 14289-2§8.2.2
Los elementos de estructura siguen un anidamiento y un orden de lectura definidos.ISO 14289-2§8.2.3
Cada elemento de estructura se resuelve a un espacio de nombres conocido, directamente o mediante asignación de roles.ISO 14289-2§8.2.4
El idioma natural se declara a nivel de documento y de elemento de estructura.ISO 14289-2§8.4.4
El contenido que no es texto lleva una alternativa textual.ISO 14289-2§8.5.1
Las celdas de tabla llevan relaciones de row/header/datos.ISO 14289-2§8.2.5.26
El marcador de PDF etiquetado es la marca MarkInfoMarked del catálogo.ISO 32000-2§14.7
La conformidad se decide frente a la parte, no la afirma el productor.ISO 14289-2§8.14.2

NextPDF emite la estructura etiquetada que facilita la autoría accesible. Facilitar no es conformidad. Esta receta no afirma la conformidad con PDF/UA-2. Un verificador independiente (por ejemplo, veraPDF) realiza esa determinación. Ejecutar el verificador antes de afirmar que un archivo es conforme.