PDF-Tags aus Coding-Sicht
Hinter jedem barrierefreien PDF steckt eine zweite, unsichtbare Ebene:
der Struktur-Baum. Dieser Artikel zeigt, wie StructTreeRoot
, StructElem
, MCIDs und der Parent-Tree zusammenspielen — und
wie eigene Tooling-Pipelines diesen Baum erzeugen, ohne dass am Ende
etwas leer durch PAC oder veraPDF fällt.
Worum geht es bei PDF-Tags?
Ein PDF zeigt auf der Seite Glyphen — also visuell positionierte Zeichen. Was es nicht aus sich heraus weiß: Welche Glyphen gehören zu einer Überschrift? Was ist ein Absatz, was eine Tabelle, was eine Bildbeschreibung? Genau diese Information liefert der Struktur-Baum — eine zweite Datenebene, die parallel zum Content-Stream im Dokument hinterlegt ist. Sie sagt assistiven Technologien, was die sichtbaren Glyphen bedeuten.
PDF/UA (ISO 14289) macht diesen Baum zur Pflicht, sobald ein PDF als barrierefrei gelten soll. PDF 2.0 (ISO 32000-2:2020) beschreibt die zugrunde liegenden Strukturen in Abschnitt 14 „Document interchange" und behandelt Tagging als integralen Teil des Formats — nicht mehr als Erweiterung wie noch in PDF 1.7. Der Tagbaum ist also keine Eigenheit eines Tools, sondern Teil der ISO-Norm.
Der Struktur-Baum: StructTreeRoot, StructElem, Kids
Im PDF-Dokumenten-Catalog gibt es einen Eintrag /StructTreeRoot
.
Dieser zeigt auf das Wurzelobjekt des Struktur-Baums. Von dort verzweigt
sich eine Hierarchie aus Struktur-Elementen(PDF-Typ /StructElem
), bis am untersten Ende konkrete Inhalte auf den
Seiten referenziert werden.
Jedes Struktur-Element ist ein Dictionary mit einem Typ, einer
Rolle (etwa /H1
, /P
, /Figure
) und
einem Kinder-Array /K
. Was im /K
steht, regelt
ISO 32000-2 Abschnitt 14.7: erlaubt sind eine Ganzzahl (eine
MCID, dazu gleich mehr), ein weiteres /StructElem
, ein
Marked-Content-Reference-Dictionary /MCR
, eine Objekt-Referenz /OBJR
— oder ein Array beliebiger dieser Varianten.
struct-element.txt — Beispiel-Knoten
5 0 obj << /Type /StructElem /S /H1 % Rolle: Überschrift Ebene 1 /P 4 0 R % Parent (Eltern-Element) /Pg 2 0 R % Seite, auf der der Inhalt liegt /K [ 0 1 ] % Kinder: zwei MCIDs auf Seite 2 /Alt (Kapitel 1 — Einleitung) >> endobj
Dieser Knoten sagt: „Ich bin eine H1, mein Elternknoten ist Objekt 4, meine inhaltlichen Glyphen liegen auf der Seite 2 (Objekt 2) mit den Marked-Content-IDs 0 und 1." Genau dort schlägt der Tagbaum die Brücke zur sichtbaren Seite.
MCIDs und der Parent-Tree
MCID steht für Marked Content Identifier. Jeder Inhaltsabschnitt auf einer Seite kann mit einer fortlaufenden Ganzzahl markiert werden. Innerhalb einer Seite sind MCIDs eindeutig; in verschiedenen Seiten können dieselben Zahlen wieder auftauchen. Sie zeigen also nicht global eindeutig auf einen Inhalt — die Eindeutigkeit entsteht erst durch die Kombination aus Seite und MCID.
Damit assistive Technologien von einem Glyph zurück zum Tag finden, gibt
es im Struktur-Baum-Wurzel ein zweites Verzeichnis: den /ParentTree
. Das ist ein Number-Tree, der pro Seite eine
Liste hält. Index in dieser Liste ist die MCID; der Wert ist eine
Referenz auf das passende /StructElem
. ISO 32000-2
Abschnitt 14.7.5 beschreibt das im Detail. Wer einmal die
iText-Dokumentation oder pikepdfs Issue 461 dazu liest, erkennt
schnell: der Parent-Tree ist eine der häufigsten Fehlerquellen in
selbstgebauten Pipelines, weil seine Index-Logik leicht aus dem Takt
gerät.
Marked Content im Stream: BDC und EMC
Die MCID selbst wird im Content-Stream geboren. PDF kennt dafür zwei
Operatoren: BDC
( Begin Marked Content with Dictionary
)
und EMC
( End Marked Content
). Alles zwischen diesen
beiden Markern gehört logisch zur gleichen MCID.
content-stream.txt — Marked-Content-Block
/H1 <</MCID 0>> BDC % Marked Content beginnt, MCID 0 BT /F1 24 Tf 72 720 Td (Kapitel 1) Tj ET EMC % Marked Content endet /P <</MCID 1>> BDC % Nächster Marked-Content-Block, MCID 1 BT /F2 11 Tf 72 690 Td (Eine kurze Einleitung.) Tj ET EMC
Der erste Operand vor BDC
ist der Tag-Name. Das nachfolgende
Dictionary enthält mindestens den Eintrag /MCID
. Diese Zahl
ist es dann, die im Struktur-Baum-Knoten unter /K
auftaucht
und im Parent-Tree als Index dient. So schließt sich der Kreis: vom
Struktur-Element zur Seite, von der Seite per Parent-Tree zurück zum
Struktur-Element.
Role-Mapping und Standard-Strukturtypen
ISO 32000-2 definiert in Abschnitt 14.8 einen Satz an Standard-Strukturtypen. Sie sind in einem Namensraum
definiert, der mit PDF 2.0 von /StandardStructureType
auf einen einheitlichen Standard-Namespace umgestellt wurde. Eigene
Tag-Namen sind erlaubt, müssen aber per /RoleMap
auf einen
Standardtyp abgebildet werden — sonst weiß die assistive Technologie
nicht, was sie damit anfangen soll.
| Tag | Bedeutung | Pflicht in PDF/UA? |
|---|---|---|
/Document
|
Wurzelelement des logischen Dokuments. | Ja — genau einmal. |
/H1
– /H6
|
Hierarchische Überschriften, von höchster (1) zu niedrigster (6) Ebene. | Eingeschränkt — /H
ohne Nummer ist deprecated in 2.0. |
/P
|
Absatz, der häufigste Block-Tag in Lauftexten. | Empfohlen für Fließtext. |
/Figure
|
Bild oder Grafik mit Alternativtext ( /Alt
) oder Bezeichnung. |
Ja, wenn relevante Bilder vorhanden. |
/Table
· /TR
· /TH
· /TD
|
Tabellenstruktur — Container, Zeile, Kopf- und Datenzelle. | Ja für Datentabellen, mit Header-Zuordnung. |
/L
· /LI
· /Lbl
· /LBody
|
Listenstruktur: Liste, Listeneintrag, Marker, Eintragsinhalt. | Empfohlen für geordnete und ungeordnete Listen. |
/Artifact
|
Inhalt ohne Bedeutung für assistive Technologien (Seitenzahlen, Hintergrundgrafiken, Trennlinien). | Ja — alles Nicht-Bedeutungstragende muss als Artifact markiert sein. |
Tooling-Pipelines: wie eigene Tags entstehen
In der Praxis gibt es drei Wege, einen PDF-Tagbaum zu erzeugen — und alle drei sind im DACH-Raum produktiv im Einsatz:
- Office-Pipelines(Word, LibreOffice, InDesign) liefern getaggte PDFs heraus, sobald die Quelle ordentlich strukturiert ist. Die Programme schreiben den Tagbaum selbst, der Quelltext der Anwender:in steuert die Rollen indirekt über die verwendeten Formatvorlagen.
- LaTeX-Tagging-Projekt. Ulrike Fischers laufende
Implementierung in LaTeX3 (Paket
tagpdf) generiert seit 2020 einen vollständigen Tagbaum aus dem LaTeX-Quelltext heraus. Der TUGboat-Artikel von 2020 beschreibt das Konzept — inklusive der Komplexität rund um den Parent-Tree, die später in einem GitHub-Issue zur Beispiel-Datei dokumentiert wurde. - Eigene Toolchain mit Bibliotheken wie pikepdf (Python/qpdf), pdf-lib (JavaScript) oder iText (Java/.NET). Hier baut man Struktur-Elemente, MCIDs und Parent-Tree von Hand — entweder beim Erzeugen eines PDF aus einem anderen Format oder beim Nachträglichen Reparieren bestehender Dateien.
Drei Annahmen — und warum sie nicht stimmen
Mythos 1: „MCIDs sind global eindeutig." Falsch. MCIDs sind nur innerhalb einer Seite eindeutig. Über Seiten hinweg können dieselben Zahlen wiederkehren — gerade deshalb braucht es den Parent-Tree mit der Seite als Schlüssel. Wer in einem Tooling versucht, MCIDs als globale IDs zu führen, baut sich eine unsichtbare Bug-Quelle.
Mythos 2: „Wenn Acrobat das PDF als getaggt anzeigt, ist es PDF/UA-konform."
Nein. Acrobat zeigt schon dann „Tagged: Yes" an, wenn ein /StructTreeRoot
existiert. PDF/UA verlangt zusätzlich
Vollständigkeit (alle bedeutungstragenden Inhalte getaggt), korrektes
Role-Mapping, eine plausible Lese-Reihenfolge und korrekte
Artifact-Markierung. „Getaggt" ist die Vorstufe, „konform" ist deutlich
mehr.
Mythos 3: „Den Tagbaum schreibt das Tool — da kann ich als Entwickler:in nichts tun." Stimmt nur halb. Die meisten Office-Werkzeuge schreiben einen Tagbaum aus den Formatvorlagen, aber Fehler in Reading Order, Artifact-Tagging oder Tabellen-Header lassen sich auf Code-Ebene mit pikepdf oder ähnlichen Bibliotheken gezielt korrigieren. Wer das einmal pro Pipeline einbaut, spart Stunden manueller Acrobat-Klickerei.
Tag-Pipeline planen oder reparieren?
Wir helfen, eigene PDF-Tagging-Pipelines zu konzipieren oder bestehende Tag-Bäume gezielt nachzubessern — vom Konzept über die Library-Wahl bis zum veraPDF-konformen Ergebnis. Schulungen für Entwickler:innen-Teams ebenso wie Audits einzelner Dokument-Klassen.
Beratung oder Schulung anfragen