Aller au contenu

Émettre une arborescence de structure balisée PDF/UA-2 à partir d'un contenu sémantique

Cette page montre comment produire un PDF balisé visant la norme ISO 14289-2 (PDF/UA-2). NextPDF émet un arbre de structure logique, des séquences de contenu balisé, la langue du catalogue et les métadonnées d’identification au niveau du document. Cette structure facilite la création de documents accessibles, mais c’est un outil de vérification indépendant qui détermine la conformité. Elle s’appuie sur examples/31-pdfua2-tagged.php.

Fenêtre de terminal
composer require nextpdf/core:^3

L’étape de vérification nécessite un outil de vérification PDF/UA-2 dans le PATH. Les exemples de cette page utilisent veraPDF avec la variante ua2. Tu n’as pas besoin d’un package Pro ou Enterprise pour émettre la structure balisée.

Un PDF balisé porte un arbre de structure logique parallèle au flux de contenu visuel. Les technologies d’assistance lisent l’arbre, pas la disposition des pixels ; c’est donc la structure qui détermine l’ordre de lecture présenté. ISO 14289-2 pose ici quatre exigences. Le contenu réel (non-artefact) doit être accessible au travers de cet arbre (§8.2.2). Les éléments de structure doivent s’imbriquer dans un ordre défini (§8.2.3). Chaque élément doit se résoudre en un espace de noms de structure connu, directement ou par mappage de rôle (§8.2.4). Enfin, la langue naturelle du contenu est déclarée au niveau du document, puis affinée par élément de structure là où elle diffère (§8.4.4).

NextPDF modélise cela avec un ConformanceMode typé. enableTaggedPdf() définit ConformanceMode::PdfUa2, ce qui (a) conduit le pipeline HTML à câbler un TaggedContentEmitter au moment de la construction du parseur, (b) active l’indicateur de catalogue MarkInfoMarked qui signale un PDF balisé (ISO 32000-2 §14.7), et (c) enregistre la langue BCP-47 pour l’entrée de catalogue Lang. Le writer émet également l’entrée Tabs par page, afin que l’ordre de tabulation suive l’ordre de la structure (ISO 32000-2 §14.8).

Les invariants stricts UA-2 s’appliquent uniquement à ConformanceMode::PdfUa2. Construire une ConformancePolicy stricte pour tout autre mode lève InvalidConfigException, et c’est voulu.

La surface d’API est générée à partir du PHPDoc. Les points d’entrée à retenir :

  • \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 (le mode défini par enableTaggedPdf())
  • Document::beginTag(string $type): static / Document::endTag(): static (balisage manuel pour le contenu non-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";

Voici le programme autonome, exécutable par le harnais. En production, l’appelant échoue tôt sur une balise de langue mal formée, au lieu de ne la découvrir qu’au moment d’exécuter l’outil de vérification externe. Passe ConformancePolicy::strictUa2() pour rejeter une balise BCP-47 invalide à la frontière de l’API, puis conditionne le build au verdict de l’outil de vérification.

<?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 attendu, sur un hôte où verapdf --flavour ua2 signale le fichier comme conforme :

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

Si enableTaggedPdf() rejette la balise de langue, le programme se termine avec un code non nul après avoir écrit Tagged PDF/UA-2 setup rejected: … sur STDERR. Si l’outil de vérification signale un problème, il se termine avec un code non nul après veraPDF FAILED — output is not PDF/UA-2 conforming. Le verdict revient à l’outil de vérification : NextPDF émet la structure, mais n’affirme pas la conformité.

  • Ordre des appels. enableTaggedPdf() après writeHtml() ne balise pas rétroactivement le contenu déjà écrit. Active d’abord le mode balisé.
  • Garde-fou strict sur la langue. Sans politique, une balise BCP-47 non analysable est ignorée silencieusement et n’apparaît qu’au moment de l’outil de vérification. Avec ConformancePolicy::strictUa2(), la même balise lève InvalidConfigException à la frontière de enableTaggedPdf() (ISO 14289-2 §8.4.4, chemin strict).
  • Réactivation idempotente. Appeler enableTaggedPdf() deux fois met à jour la langue sans reconstruire un arbre de structure déjà peuplé.
  • Balisage manuel. Pour le contenu non-HTML, encadre les éléments avec beginTag() / endTag(). Les rôles de conteneur (Table, TR, L, LI) deviennent des éléments de regroupement sans contenu balisé. Les rôles feuilles (P, H1H6, TD) reçoivent des MCID.
  • Exclusivité des modes. Une ConformancePolicy stricte n’est valide qu’avec ConformanceMode::PdfUa2. Combiner des indicateurs stricts UA-2 avec un mode PDF/A lève InvalidConfigException. Produis un livrable PDF/A balisé en activant le mode balisé et le profil PDF/A séparément.

L’arbre de structure ajoute un arbre parallèle de dictionnaires légers, plus des opérateurs BDC/EMC pour chaque séquence de texte. Pour un rapport classique, le surcoût représente quelques pour cent de la taille de sortie et reste largement dans le budget de 2000 ms / 128 Mo. Le profil de reproductibilité sémantique s’applique ici, car un livrable destiné à un outil de vérification se compare par arbre de syntaxe abstraite (AST) structurel et métadonnées, plutôt que par octets bruts. Voir la section Conformité.

Résidence des données & atténuations relatives aux PII

Section intitulée « Résidence des données & atténuations relatives aux PII »

L’arbre de structure contient le même texte que le contenu visible. Si le HTML source contient des données personnelles, ces données sont aussi accessibles au travers de l’arbre et via les attributs ActualText/Alt. Applique la même expurgation et la même minimisation avant la production que celles que tu appliquerais au contenu visible. Le balisage n’ajoute aucun nouveau chemin d’exfiltration, mais il rend effectivement le texte extractible par programme, par conception.

L’exemple n’écrit qu’une ligne de progression fixe sur STDOUT. Il envoie le PDF vers le canal auxiliaire du harnais (NEXTPDF_COOKBOOK_OUTPUT) ou vers un chemin fourni par l’appelant. Le texte du document n’est jamais journalisé. Garde la sortie de l’outil de vérification, qui peut contenir des fragments de contenu, hors des journaux partagés.

Un PDF balisé n’est pas une frontière de confiance. Un consommateur qui s’appuie sur l’arbre de structure pour un traitement automatisé doit quand même valider le fichier, car un producteur hostile peut émettre un arbre structurellement bien formé mais trompeur. Traite la structure comme une aide à l’accessibilité, pas comme un signal d’intégrité ou d’authenticité.

L’exemple n’effectue aucune opération cryptographique. Le mode FIPS ne change pas son comportement. Aucune signature ni aucun chiffrement n’est en jeu.

Exigence PDF/UA-2Ce que NextPDF émetArticle
Le contenu réel se trouve dans l’arbre de structureStructTreeRoot avec un StructElem par bloc et un contenu balisé lié par MCIDISO 14289-2 §8.2.2
Imbrication et ordre de lecture définisÉléments de bloc mappés vers des rôles grouping/leaf dans l’ordre du documentISO 14289-2 §8.2.3
Espace de noms de structure connuRôles dans l’espace de noms PDF 2.0 ; balises HTML mappées par rôle là où c’est nécessaireISO 14289-2 §8.2.4
Langue du document et de l’élémentDans le catalogue, Lang issu de la balise BCP-47 ; Lang par élément quand elle diffèreISO 14289-2 §8.4.4
Le contenu non textuel a une alternative textuelleAlt/ActualText portés sur les éléments de structure figure/non-textISO 14289-2 §8.5.1
Relations de tableauTable/TR/TH/TD, rôles avec associations d’en-têteISO 14289-2 §8.2.5.26
Métadonnées d’identification de la partieIdentification au niveau du document, planifiée à l’enregistrementISO 14289-2 §Intro (pdfua2#p17)

PDF/UA-2 superpose des exigences d’accessibilité aux mécanismes de PDF balisé d’ISO 32000-2. Le mappage sur lequel NextPDF s’appuie :

Émission NextPDFDispositif ISO 32000-2 §14Article
Arbre de structure logique (StructTreeRoot)Structure logique du PDF balisé§14.7 (iso32000_2_sec14#x1.x38.p13)
Dans le catalogue, MarkInfo << /Marked true >>Marqueur de PDF balisé§14.7 (iso32000_2_sec14#x1.x40.p3)
Entrée Tabs par page suivant l’ordre de la structureNavigation structurelle / ordre de tabulation§14.8 (iso32000_2_sec14#x1.x50)

PDF/UA-2 est l’expression, en PDF, d’exigences de structure que WCAG 2.2 énonce de manière indépendante du format. L’alignement pertinent :

Critère de succès WCAG 2.2Mécanisme PDF/UA-2 produit ici
1.3.1 Information et relations (niveau A)L’arbre de structure rend les titres, les listes et les relations de tableau déterminables par programme (wcag_2_2#x2.x3.x3.x1.p3).
1.3.2 Séquence significative (niveau A)L’ordre de la structure définit l’ordre de lecture, indépendamment de la disposition visuelle.
3.1.1 Langue de la page (niveau A)L’entrée Lang du catalogue à partir de la balise BCP-47.
1.1.1 Contenu non textuel (niveau A)Alt/ActualText sur les éléments de structure non textuels (ISO 14289-2 §8.5.1).

Ce mappage montre où la structure émise prend en charge un critère WCAG 2.2. Il ne constitue pas une revendication de conformité WCAG. La conformité WCAG couvre toute l’expérience utilisateur et se détermine par une évaluation d’accessibilité, pas par le producteur.

ÉnoncéSpécificationArticlereference_id
Le contenu réel exige une structure logique.ISO 14289-2§8.2.2
Les éléments de structure suivent une imbrication et un ordre de lecture définis.ISO 14289-2§8.2.3
Chaque élément de structure se résout en un espace de noms connu, directement ou par mappage de rôle.ISO 14289-2§8.2.4
La langue naturelle est déclarée au niveau du document et de l’élément de structure.ISO 14289-2§8.4.4
Le contenu non textuel porte une alternative textuelle.ISO 14289-2§8.5.1
Les cellules de tableau portent des relations row/header/données.ISO 14289-2§8.2.5.26
Le marqueur de PDF balisé est l’indicateur de catalogue MarkInfoMarked.ISO 32000-2§14.7
La conformité se décide par rapport à la partie, elle n’est pas affirmée par le producteur.ISO 14289-2§8.14.2

NextPDF émet la structure balisée qui prend en charge une production accessible. La prise en charge ne vaut pas conformité. Cette page n’affirme pas la conformité PDF/UA-2. C’est un outil de vérification indépendant (par exemple veraPDF) qui établit ce verdict. Exécute l’outil de vérification avant d’affirmer qu’un fichier est conforme.