Zum Inhalt springen

Barrierefreiheit: Tagging-Primitive und PDF/UA-2-Strukturmodell

NextPDF Core stellt Primitive bereit, die barrierefreies Authoring unterstützen: einen logischen Strukturbaum, standardisiertes Role-Mapping, Marked-Content-Tagging und BCP-47-Sprachattribute im Einklang mit dem Strukturbaum-Modell aus ISO 14289-2 (PDF/UA-2) und ISO 32000-2 §14.7. Die Konformität der erzeugten Datei ist eine Eigenschaft des fertigen Dokuments, der inhaltlichen Entscheidungen der Autorinnen und Autoren sowie eines externen Prüfers. Sie ist keine Zusicherung, die die Bibliothek in Ihrem Namen abgibt.

Terminal-Fenster
composer require nextpdf/core

Ein getaggtes PDF enthält einen logischen Strukturbaum, dessen Wurzel ein einziges Document-Strukturelement enthält. Assistive Technologien lesen diesen Baum, um eine sinnvolle Lesereihenfolge unabhängig vom visuellen Layout abzuleiten (ISO 32000-2 §14.7.2; ISO 14289-2 §8.2.5.2). NextPDF modelliert dies mit drei zusammenwirkenden Typen im Namespace NextPDF\Accessibility.

StructureTree verwaltet die Hierarchie, vergibt Marked-Content-Identifier pro Seite, verfolgt die Eltern-Kind-Verschachtelung und serialisiert die Wurzel des Strukturbaums, die Strukturelemente, den Parent-Tree, die Role-Map sowie den PDF 2.0-Standard-Struktur-Namespace gemäß ISO 32000-2 §14.7. createRoot() legt das obligatorische einzelne Document-Element mit einem Sprachattribut an. addElement() hängt typisierte Kindelemente an. hasRoot() und rootHasChildren() geben zurück, ob der Baum existiert und ob er Nachfahren hat.

StructureElement ist das Value Object für ein Strukturelement-Dictionary. Es erfasst den Standard-Strukturtyp (Namen aus Tabelle 368 wie H1 bis H6, P, L, LI, Table, Figure, Link), die Marked-Content-Identifier-Einträge sowie die optionalen Barrierefreiheitsattribute für Alternativtext, Ersatztext, Titel und Sprache. Ein einzelnes Element kann sich über mehrere Seiten erstrecken und pro Seite einen Identifier-Eintrag sammeln, sodass das Kids-Array über Seitengrenzen hinweg auf Marked Content verweist.

TaggedContentEmitter verbindet die HTML-Pipeline mit dem Strukturbaum. Wenn Document::enableTaggedPdf() aktiv ist, bindet der HTML-Renderer den Emitter so ein, dass Elemente auf Blockebene gepaarte Marked-Content-Operatoren mit zugehörigen Strukturelement-Knoten erzeugen. HtmlToStructureMap liefert die tabellengesteuerte Zuordnung vom HTML-Tag zum PDF-Strukturtyp (ISO 14289-2 §8). Der Emitter leitet dekorative laufende Inhalte wie die HTML-Kopf- und Fußzeilenbereiche als Artifact um, wodurch sie aus der Lesereihenfolge herausgehalten werden.

Das Sprach-Tagging wird von Bcp47Validator validiert (RFC 5646). Er bietet eine syntaktische Prüfung auf Wohlgeformtheit und eine registrygestützte Gültigkeitsprüfung. Der Strict-Modus (ConformancePolicy::strictUa2()) lehnt ungültige Tags an der API-Grenze ab, anstatt sie beim Schreiben stillschweigend zu verwerfen. Das entspricht der Anforderung aus ISO 14289-2 §8.4.4, dass der Sprach-Eintrag im Catalog auf eine konkrete Sprache aufgelöst werden muss.

SymbolArtZusammenfassung
Document::enableTaggedPdf(string $lang = 'en', ?ConformancePolicy $policy = null): staticMethodeAktiviert den Strukturbaum und die HTML-Brücke; setzt die Mark-Info- und die Catalog-Sprach-Einträge.
Document::setLanguage(string $lang): staticMethodeSetzt die natürliche Sprache auf Dokumentebene (BCP-47).
Document::isTaggedPdfEnabled(): boolMethodeGibt an, ob der aktive Konformitätsmodus strukturelles Tagging vorschreibt.
StructureTree::createRoot(string $lang = 'en'): intMethodeErzeugt das obligatorische einzelne Document-Wurzelelement.
StructureTree::addElement(int $parentIndex, string $type, int $pageIndex, ...): intMethodeHängt ein typisiertes Kind-Strukturelement an.
StructureTree::hasRoot(): bool und rootHasChildren(): boolMethodePrüfen, ob der Baum existiert und ob er Nachfahren hat.
StructureElementfinal classValue Object für ein Strukturelement (Alternativtext, Ersatztext, Titel, Sprache, Identifier).
RoleMap::standard(): array<string,string>staticStandard-Strukturtyp-Vokabular (ISO 32000-2 Tabelle 368 plus PDF 2.0-Typen).
Bcp47Validator::isWellFormed/isValid/validate/normaliseMethodeSyntaktische und registrygestützte Validierung von Sprach-Tags nach RFC 5646.
AccessibilityAutoFixerRegistryfinal classOpt-in-Registry im PSR-11-Stil für heuristische Struktur-Fixer.
<?php
declare(strict_types=1);
use NextPDF\Core\Document;
$doc = Document::createStandalone();
// The BCP 47 tag drives the catalog language entry and the
// structure-tree root language attribute.
$doc->enableTaggedPdf(lang: 'en');
$doc->setTitle('Tagged accessibility demo');
$doc->addPage();
// Semantic HTML maps to structure elements: h1 to /H1, p to /P,
// ul and li to /L plus /LI. Text runs are wrapped in
// marked-content operators with stable identifiers.
$doc->writeHtml('<h1>Document title</h1><p>Body paragraph.</p>');
$doc->save(__DIR__ . '/output/tagged.pdf');
<?php
declare(strict_types=1);
use NextPDF\Conformance\ConformancePolicy;
use NextPDF\Core\Document;
use NextPDF\Exception\InvalidConfigException;
use Psr\Log\LoggerInterface;
final class AccessibleReportWriter
{
public function __construct(private readonly LoggerInterface $logger)
{
}
public function render(string $html, string $bcp47Lang, string $outPath): void
{
$doc = Document::createStandalone();
try {
// strictUa2() rejects malformed BCP 47 tags at the API
// boundary (ISO 14289-2 §8.4.4) instead of dropping silently.
$doc->enableTaggedPdf($bcp47Lang, ConformancePolicy::strictUa2());
} catch (InvalidConfigException $e) {
$this->logger->error('Rejected language tag for tagged PDF', [
'lang' => $bcp47Lang,
'reason' => $e->getMessage(),
]);
throw $e;
}
$doc->setTitle('Quarterly accessibility report')
->setLanguage($bcp47Lang)
->addPage();
$doc->writeHtml($html);
// The engine emits a Degraded / ComplianceRisk advisory directing
// the caller to validate externally; surface it to operators
// rather than treating tagged output as certified.
foreach ($doc->getWarnings() as $warning) {
$this->logger->warning('Tagged-PDF advisory', [
'code' => $warning->code->value,
'message' => $warning->message,
]);
}
$doc->save($outPath);
}
}
  • Reihenfolge der Aufrufe. Rufen Sie enableTaggedPdf() vor writeHtml() auf. Die HTML-Pipeline prüft den Konformitätsmodus beim Aufbau des Parsers und bindet den Emitter nicht rückwirkend für bereits gerenderte Inhalte ein.
  • Leerer Strukturbaum. Ein Dokument mit enableTaggedPdf(), aber ohne angehängte Struktur-Nachfahren weist PDF/UA-2 nicht in seinen Metadaten aus. Das Veröffentlichungs-Gate ist rootHasChildren(), nicht hasRoot(), weil Validatoren eine Datei ablehnen, die PDF/UA-2 mit einem leeren Strukturbaum behauptet (ISO 14289-2 §5; verifiziert durch EmptyTaggedPdfDoesNotAdvertisePdfUa2Test).
  • Kollaps des Konformitätsmodus. Der Aufruf von enablePdfA() und enableTaggedPdf() auf demselben Dokument lässt den einwertigen Konformitätsdiskriminator auf „Last-Wins“ zusammenfallen. Die Seiteneffekte (Strukturbaum, Mark-Info) bleiben additiv, und es wird eine CONFORMANCE_MODE_CLOBBERED-Warnung ausgegeben, sodass der Kollaps beobachtbar ist.
  • Auto-Fixer laufen nicht automatisch. Die integrierten Fixer (EmptyTagStripper, LegacyLangNormaliser, RootLangFallback) werden unter NextPDF\Accessibility\AutoFixer\* ausgeliefert, aber niemals automatisch registriert. Der Consumer muss sie explizit bei AccessibilityAutoFixerRegistry registrieren.

NextPDF gibt eine Struktur aus, die mit dem PDF/UA-2-Strukturbaum-Modell konsistent ist, erzeugt aber keine Semantik automatisch, die es nicht ableiten kann. Das Folgende erfordert Markup oder Attribute, die von Autorinnen oder Autoren bereitgestellt werden, und wird nicht für Sie erzeugt:

  • Alternativtext für Bilder und andere Nicht-Text-Inhalte;
  • Tabellen-Header-Bereich und die Zuordnung von Header zu Zelle über das hinaus, was das HTML-Markup ausdrückt;
  • Text zum Linkzweck, wenn der sichtbare Linktext nicht selbsterklärend ist;
  • Listensemantik für Inhalte, die visuell als Liste angeordnet sind, aber kein Listen-Markup haben;
  • eine korrigierte Lesereihenfolge, wenn die Quellreihenfolge von der beabsichtigten Lesereihenfolge abweicht;
  • die Einordnung mehrdeutiger Inhalte als dekorativ oder bedeutungstragend.

Die Bibliothek führt keine vollständige PDF/UA-2-Verifikation durch. Die Laufzeit selbst gibt einen Hinweis vom Typ Degraded / ComplianceRisk aus (PDFUA2_FOUNDATIONAL), der die aufrufende Stelle anweist, die Ausgabe vor der produktiven Freigabe mit einem externen Prüfer zu validieren. Validieren Sie mit einem PDF/UA-Prüfer (zum Beispiel veraPDF). NextPDF sichert die Konformität nicht in Ihrem Namen zu. Die Konformität des fertigen Dokuments hängt von den Authoring-Entscheidungen und einem Validator ab, nicht vom Aufruf der API.

Die Konstruktion des Strukturbaums ist linear in der Anzahl der Strukturelemente. Die Identifier-Vergabe ist pro Marked-Content-Sequenz amortisiert konstant. Die Serialisierung erfolgt in einem einzelnen linearen Durchlauf über die Elementmenge. Der dominierende Kostenfaktor beim HTML-gesteuerten Tagging ist die HTML-Pipeline selbst, nicht die Tag-Ausgabe. Das in performance_budget deklarierte Limit pro Recipe (1500 ms Wall-Time, 64 MB Peak) gilt für ein typisches mehrseitiges semantisches Dokument. Große Dokumente skalieren linear mit der Elementanzahl, nicht mit der Seitenanzahl.

Sprach-Tags und Barrierefreiheitsattribute fließen in PDF-Name- und PDF-String-Objekte ein. NextPDF maskiert sie über PdfStringEscaper, sodass ungültige oder bösartige Werte für Sprache, Alternativtext, Ersatztext und Titel nicht aus ihrem PDF-Objektkontext ausbrechen können. Der Strict-Modus lehnt zusätzlich nicht registrierte BCP-47-Tags an der API-Grenze ab und engt so die Eingabefläche ein, bevor sie den Writer erreicht. Barrierefreiheitsattribute können Freitext enthalten, den Autorinnen oder Autoren bereitgestellt haben. Behandeln Sie sie als nicht vertrauenswürdige Ausgabe und wenden Sie dieselbe Prüfung an, die Sie auch auf andere Dokumentinhalte anwenden. Siehe das Conformance-Modul für das Verhalten der Profil-Prüfer.

Diese Seite ordnet das Verhalten der Bibliothek den Clause-Identifiern zu. Sie behauptet nicht, dass Ihre Ausgabe konform ist. Die zitierten Clauses werden paraphrasiert und niemals wörtlich zitiert. Siehe das PDF/UA-2-Spezifikations-Mapping für die Tabelle auf Provision-Ebene und die ausdrücklich nicht abgedeckten Bereiche. Die Hash-Werte der Citation-Chunks sind in docs/public/modules/core/_normative-evidence-a11y.md festgehalten.