Salta ai contenuti

Generare un albero della struttura PDF/UA-2 con tag da contenuto semantico

Questa ricetta crea un PDF con tag conforme a ISO 14289-2 (PDF/UA-2). NextPDF genera un albero della struttura logica, le sequenze di contenuto marcato, la lingua del catalogo e i metadati di identificazione a livello di documento. Questa struttura supporta la creazione accessibile, ma la conformità viene stabilita da un checker indipendente. La ricetta si basa su examples/31-pdfua2-tagged.php.

Terminal window
composer require nextpdf/core:^3

La verifica richiede un checker PDF/UA-2 in PATH. Gli esempi di questa ricetta usano veraPDF con il profilo ua2. Non serve un pacchetto Pro o Enterprise per generare la struttura con tag.

Un PDF con tag include un albero della struttura logica parallelo al flusso del contenuto visivo. Le tecnologie assistive leggono l’albero, non l’impaginazione dei pixel; è quindi la struttura a determinare l’ordine di lettura esposto. ISO 14289-2 definisce qui quattro requisiti. Il contenuto reale (non artifact) deve essere raggiungibile attraverso questo albero (§8.2.2). Gli elementi di struttura devono annidarsi secondo un ordine definito (§8.2.3). Ogni elemento deve risolversi in un namespace di struttura noto, direttamente o tramite role mapping (§8.2.4). Inoltre, la lingua naturale del contenuto è dichiarata a livello di documento e raffinata per singolo elemento di struttura quando differisce (§8.4.4).

NextPDF modella questo comportamento con un ConformanceMode tipizzato. enableTaggedPdf() imposta ConformanceMode::PdfUa2, che (a) fa sì che la pipeline HTML colleghi un TaggedContentEmitter al momento della costruzione del parser, (b) attiva il flag MarkInfoMarked del catalogo che segnala un PDF con tag (ISO 32000-2 §14.7) e (c) registra la lingua BCP-47 per la voce Lang del catalogo. Il writer genera inoltre la voce Tabs per ogni pagina, affinché l’ordine di tabulazione segua l’ordine della struttura (ISO 32000-2 §14.8).

Gli invarianti stretti UA-2 si applicano solo a ConformanceMode::PdfUa2. Costruire una ConformancePolicy stretta per qualsiasi altra modalità genera InvalidConfigException per impostazione progettuale.

La superficie API è generata dal PHPDoc. I principali punti di ingresso sono:

  • \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 (la modalità impostata da enableTaggedPdf())
  • Document::beginTag(string $type): static / Document::endTag(): static (assegnazione manuale dei tag per contenuto 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";

Questo è il programma autonomo, eseguibile dall’harness. In produzione, il chiamante fallisce subito su un tag di lingua malformato, invece di scoprirlo solo quando viene eseguito il checker esterno. Passare ConformancePolicy::strictUa2() per rifiutare un tag BCP-47 non valido al confine dell’API, quindi subordinare la build al verdetto del checker.

<?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 atteso, su un host in cui verapdf --flavour ua2 riporta il file come conforme:

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

Se enableTaggedPdf() rifiuta il tag di lingua, il programma termina con codice diverso da zero dopo Tagged PDF/UA-2 setup rejected: … su STDERR. Se il checker segnala un problema, termina con codice diverso da zero dopo veraPDF FAILED — output is not PDF/UA-2 conforming. Il verdetto spetta al checker: NextPDF genera la struttura ma non asserisce la conformità.

  • Ordine delle chiamate. enableTaggedPdf() dopo writeHtml() non applica retroattivamente i tag al contenuto già scritto. Attivare prima la modalità con tag.
  • Gate stretto sulla lingua. In assenza di un criterio, un tag BCP-47 non analizzabile viene scartato in modo silenzioso ed emerge solo al momento del checker. Con ConformancePolicy::strictUa2() lo stesso tag genera InvalidConfigException al confine di enableTaggedPdf() (ISO 14289-2 §8.4.4 percorso stretto).
  • Riattivazione idempotente. Chiamare enableTaggedPdf() due volte aggiorna la lingua senza ricostruire un albero della struttura già popolato.
  • Assegnazione manuale dei tag. Per contenuto non HTML, racchiudere gli elementi con beginTag() / endTag(). I ruoli contenitore (Table, TR, L, LI) diventano elementi di raggruppamento senza contenuto marcato. I ruoli foglia (P, H1H6, TD) ottengono gli MCID.
  • Esclusività delle modalità. Una ConformancePolicy stretta è valida solo con ConformanceMode::PdfUa2. La combinazione di flag UA-2 stretti con una modalità PDF/A genera InvalidConfigException. Per comporre un deliverable PDF/A con tag, attivare la modalità con tag e il profilo PDF/A separatamente.

L’albero della struttura aggiunge un albero parallelo di dizionari leggeri più gli operatori BDC/EMC per ciascuna sequenza di testo. In un report tipico, l’overhead è di qualche punto percentuale della dimensione di output e resta ampiamente entro il budget di 2000 ms / 128 MB. Qui si applica il profilo di riproducibilità semantica, perché un deliverable orientato al checker viene confrontato in base a un albero di sintassi astratta (AST) strutturale e ai metadati, non ai byte grezzi. Vedere la sezione Conformità.

L’albero della struttura contiene lo stesso testo del contenuto visibile. Se l’HTML di origine contiene dati personali, tali dati sono raggiungibili anche attraverso l’albero e tramite gli attributi ActualText/Alt. Applicare lo stesso oscuramento e la stessa minimizzazione prima della creazione, come si farebbe per il contenuto visibile. L’assegnazione dei tag non aggiunge alcun nuovo percorso di esfiltrazione, ma rende il testo estraibile in modo programmatico per impostazione progettuale.

La ricetta scrive su STDOUT solo una riga fissa di avanzamento. Instradare il PDF al canale laterale dell’harness (NEXTPDF_COOKBOOK_OUTPUT) o a un percorso del chiamante. Il testo del documento non viene mai registrato nei log. Tenere l’output del checker, che può riportare frammenti di contenuto, fuori dai log condivisi.

Un PDF con tag non è un confine di fiducia. Un consumatore che si fida dell’albero della struttura per l’elaborazione automatica deve comunque convalidare il file, perché un produttore ostile può generare un albero strutturalmente ben formato ma fuorviante. Considerare la struttura un’affordance di accessibilità, non un segnale di integrità o autenticità.

Questa ricetta non esegue alcuna operazione crittografica. La modalità FIPS non ne modifica il comportamento. Non è coinvolta alcuna firma o cifratura.

Requisito PDF/UA-2Ciò che genera NextPDFClausola
Il contenuto reale è nell’albero della strutturaStructTreeRoot con StructElem per blocco e contenuto marcato collegato tramite MCIDISO 14289-2 §8.2.2
Annidamento e ordine di lettura definitiElementi di blocco mappati a ruoli grouping/leaf nell’ordine del documentoISO 14289-2 §8.2.3
Namespace di struttura notoRuoli nel namespace PDF 2.0; tag HTML mappati ai ruoli dove necessarioISO 14289-2 §8.2.4
Lingua del documento e dell’elementoDal catalogo, Lang ricavato dal tag BCP-47; Lang per elemento quando differisceISO 14289-2 §8.4.4
Il contenuto non testuale ha un’alternativa testualeAlt/ActualText applicati agli elementi di struttura figure/non-textISO 14289-2 §8.5.1
Relazioni di tabellaTable/TR/TH/TD ruoli con associazione delle intestazioniISO 14289-2 §8.2.5.26
Metadati di identificazione della parteIdentificazione a livello di documento pianificata al salvataggioISO 14289-2 §Intro (pdfua2#p17)

PDF/UA-2 sovrappone requisiti di accessibilità al meccanismo dei PDF con tag di ISO 32000-2. La mappatura su cui si basa NextPDF:

Generazione NextPDFFunzionalità ISO 32000-2 §14Clausola
Albero della struttura logica (StructTreeRoot)Struttura logica del PDF con tag§14.7 (iso32000_2_sec14#x1.x38.p13)
Catalogo MarkInfo << /Marked true >>Marcatore per PDF con tag§14.7 (iso32000_2_sec14#x1.x40.p3)
Voce Tabs per pagina che segue l’ordine della strutturaNavigazione strutturale / ordine di tabulazione§14.8 (iso32000_2_sec14#x1.x50)

PDF/UA-2 è l’espressione, in formato PDF, dei requisiti di struttura che WCAG 2.2 esprime in modo indipendente dal formato. L’allineamento pertinente:

Criterio di successo WCAG 2.2Meccanismo PDF/UA-2 prodotto da questa ricetta
1.3.1 Informazioni e relazioni (Livello A)L’albero della struttura rende le intestazioni, gli elenchi e le relazioni di tabella determinabili in modo programmatico (wcag_2_2#x2.x3.x3.x1.p3).
1.3.2 Sequenza significativa (Livello A)L’ordine della struttura definisce l’ordine di lettura indipendentemente dall’impaginazione visiva.
3.1.1 Lingua della pagina (Livello A)La voce Lang del catalogo dal tag BCP-47.
1.1.1 Contenuto non testuale (Livello A)Alt/ActualText sugli elementi di struttura non testuali (ISO 14289-2 §8.5.1).

Questa mappatura mostra dove la struttura generata supporta un criterio WCAG 2.2. Non è un’asserzione di conformità WCAG. La conformità WCAG riguarda l’intera esperienza utente ed è determinata da una valutazione di accessibilità, non dal produttore.

AffermazioneSpecificaClausolareference_id
Il contenuto reale richiede una struttura logica.ISO 14289-2§8.2.2
Gli elementi di struttura seguono un annidamento e un ordine di lettura definiti.ISO 14289-2§8.2.3
Ogni elemento di struttura si risolve in un namespace noto, direttamente o tramite role mapping.ISO 14289-2§8.2.4
La lingua naturale è dichiarata a livello di documento e di elemento di struttura.ISO 14289-2§8.4.4
Il contenuto non testuale porta un’alternativa testuale.ISO 14289-2§8.5.1
Le celle di tabella portano relazioni row/header/data.ISO 14289-2§8.2.5.26
Il marcatore di PDF con tag è il flag MarkInfoMarked del catalogo.ISO 32000-2§14.7
La conformità è decisa rispetto alla parte, non asserita dal produttore.ISO 14289-2§8.14.2

NextPDF genera la struttura con tag che supporta la creazione accessibile. Il supporto non è conformità. Questa ricetta non asserisce la conformità PDF/UA-2. A determinarla è un checker indipendente (per esempio veraPDF). Eseguire il checker prima di dichiarare che un file è conforme.