PDF-Coding · Analyse

PDFs analysieren mit qpdf und pikepdf

Wer wissen will, warum ein PDF nicht das tut, was es soll (ein Tag fehlt, eine Lese-Reihenfolge ist verdreht, ein Span -Tag verweist ins Leere), kommt um eine Inspektion auf Objekt-Ebene nicht herum. qpdf macht den binären PDF-Inhalt lesbar; pikepdf macht ihn skriptfähig. Beide Werkzeuge sind frei und ergänzen sich gut.

  • 11 Minuten Lesezeit
  • Stand: Mai 2026

Warum PDFs auf Objekt-Ebene inspizieren?

Ein PDF ist im Kern eine geordnete Sammlung von Objekten: Dictionaries, Streams, Arrays, indirekt referenziert über eine Cross-Reference-Tabelle. Authoring-Werkzeuge wie Word, InDesign oder LaTeX erzeugen diese Strukturen aus dem Quelldokument. Wenn etwas im Ergebnis nicht stimmt, etwa eine Tabelle ohne /Table -Tag, ein Bild ohne Alternativtext oder eine Lese-Reihenfolge, die quer durch die Seite springt, sieht man die Ursache nicht in der grafischen Vorschau. Sie liegt eine Ebene tiefer.

Hier setzen qpdf und pikepdf an. qpdf ist eine seit 2008 entwickelte C++-Bibliothek mit Kommandozeilen-Werkzeug, die ein PDF in eine sogenannte QDF-Form bringt: dieselbe Datei, nur ohne Komprimierung und mit lesbarem Klartext. pikepdf ist eine Python-Bindings-Schicht genau auf qpdf. Sie erlaubt dasselbe, nur eben aus einem Python-Skript heraus und mit komfortablem Zugriff auf die Objektstruktur.

qpdf: das PDF lesbar machen

qpdf bietet auf der Kommandozeile zwei Operationen, die für die Inspektion essentiell sind: --qdf (oft kombiniert mit --object-streams=disable ) und --json . Beide arbeiten verlustfrei. Das Ergebnis ist semantisch identisch zum Original, nur in einer textuellen Form.

qpdf-shell.txt: typische Aufrufe

 # 1. Datei in lesbare QDF-Form bringen 
 qpdf --qdf --object-streams=disable input.pdf output.qdf 
   
 # 2. PDF als JSON-Struktur ausgeben (qpdf 10+) 
 qpdf --json=2 input.pdf > struktur.json 
   
 # 3. Strukturelle Konsistenz prüfen 
 qpdf --check input.pdf 
   
 # 4. Einzelne Seiten herauslösen, z. B. zur Mikro-Analyse 
 qpdf --pages input.pdf 1 -- nur-seite-1.pdf 

Die QDF-Form ist die schnellste Brücke zur Lesbarkeit. Sie löst Object-Streams auf, dekomprimiert Content-Streams und schreibt jedes Objekt mit lesbaren Zeilenumbrüchen. Wer diese Datei in einem Editor öffnet, findet darin alle Strukturen aus PDF-Aufbau aus Coding-Perspektive wieder: Catalog, StructTreeRoot, Seitenobjekte, Content-Streams. Die offizielle qpdf-Dokumentation beschreibt das in Kapitel 3 „QDF Mode" im Detail.

pikepdf: das PDF skriptfähig machen

pikepdf nutzt qpdf intern und stellt die Objektstruktur als Python-Dictionary-ähnliche Datenstruktur zur Verfügung. Damit lässt sich ein PDF nicht nur lesen, sondern auch gezielt verändern, etwa neue Felder setzen, Tags umordnen oder Metadaten korrigieren, und anschließend in derselben Sitzung wieder schreiben.

pikepdf-basics.py: Datei öffnen und Objekte lesen

 import pikepdf 
   
 # PDF öffnen, als Context-Manager schließt sich die Datei sauber 
 with pikepdf.Pdf.open("input.pdf") as pdf: 
   
     # Document-Catalog (Wurzelobjekt) holen 
     catalog = pdf.Root 
     print(catalog.keys()) 
     # ['/Type', '/Pages', '/StructTreeRoot', '/MarkInfo', '/Lang', ...] 
   
     # Sprache (wichtig für Screenreader) korrigieren 
     catalog.Lang = pikepdf.String("de-DE") 
   
     # MarkInfo prüfen, signalisiert getaggtes PDF 
     mark_info = catalog.MarkInfo 
     print(mark_info.Marked)  # True / False 
   
     # Datei speichern 
     pdf.save("output.pdf") 

pikepdf verwaltet die binär codierten PDF-Objekte transparent: Strings werden bei Bedarf automatisch zwischen den PDF-Codierungen und Python umgesetzt, Object-Referenzen lassen sich wie verschachtelte Dictionaries navigieren. Die offizielle Dokumentation auf pikepdf.readthedocs.io beschreibt im Tutorial-Abschnitt „Working with metadata" und „Object model" die wichtigsten Patterns.

Ein Praxis-Workflow: vom Symptom zur Korrektur

In der Praxis folgt die Analyse oft demselben Ablauf, unabhängig davon, ob das Symptom ein PAC-Fehler oder eine veraPDF-Meldung ist:

  1. qpdf-Check. Strukturelle Konsistenz prüfen ( qpdf --check ). Wenn schon hier Fehler auftauchen, ist die Datei kaputt. Nichts weiter testen, erst reparieren.
  2. QDF-Form öffnen. Mit qpdf --qdf in eine lesbare Form bringen und in einem Editor ansehen. Catalog, StructTreeRoot und betroffene Seite suchen.
  3. Objektbaum traversieren. Mit pikepdf den Struktur-Baum durchlaufen und gezielt die Stelle suchen, an der das Symptom liegt: fehlender Tag, falsche Rolle, leere Alternativtext-Property.
  4. Gezielt korrigieren. Den betroffenen Knoten mit pikepdf neu setzen und das PDF speichern.
  5. Validator erneut laufen lassen. Mit veraPDF oder PAC prüfen, ob der Befund verschwunden ist.
Praxis-Workflow PDF-Analyse Ein Ablaufdiagramm mit fünf horizontalen Schritten von links nach rechts. Schritt 1: qpdf-Check. Schritt 2: QDF-Form öffnen. Schritt 3: pikepdf-Inspektion. Schritt 4: gezielte Korrektur. Schritt 5: Validator-Check. Jeder Schritt ist ein gerundetes Rechteck mit Karmin-Rahmen, dazwischen Pfeile. PRAXIS-WORKFLOW 1. qpdf-Check strukturell 2. QDF-Form lesbar machen 3. pikepdf Stelle finden 4. Korrektur und speichern 5. Check veraPDF/PAC bei Bedarf erneut iterieren
Fünf Schritte vom strukturellen Konsistenz-Check bis zur Validator- Bestätigung. Bei größeren Korrekturen läuft die Schleife mehrfach.

Den Struktur-Baum inspizieren

Im Wissensseiten-Strang ist es Schritt 3, die pikepdf-Inspektion, der konkret werden muss. Die folgenden Code-Schnipsel zeigen ein typisches Vorgehen: vom StructTreeRoot aus den Baum traversieren, alle StructElem -Knoten sammeln, die Verteilung der Tag-Rollen prüfen.

tagtree-inspect.py: Rollen-Histogramm

 import pikepdf 
 from collections import Counter 
   
 def walk(node, counts): 
     rolle = str(node.get("/S", "<ohne /S>")) 
     counts[rolle] += 1 
     kids = node.get("/K", []) 
     if isinstance(kids, pikepdf.Array): 
         for kid in kids: 
             if isinstance(kid, pikepdf.Dictionary): 
                 walk(kid, counts) 
   
 with pikepdf.Pdf.open("input.pdf") as pdf: 
     root = pdf.Root.StructTreeRoot 
     counts = Counter() 
     for kid in root.K: 
         walk(kid, counts) 
     for rolle, anzahl in counts.most_common(): 
         print(f"{rolle}: {anzahl}") 
   
 # Beispiel-Ausgabe 
 # /P: 47 
 # /H2: 6 
 # /Figure: 3 
 # /Span: 12 
 # /Document: 1 

Schon das Histogramm zeigt typische Befunde: Ein PDF, das laut Layout eine Tabelle enthält, in dem aber kein /Table -Knoten vorkommt, hat das Tagging schlicht nicht. Ein PDF mit /Figure -Knoten, die kein /Alt -Property tragen, scheitert an PDF/UA. Wer hier vor dem Schreiben von Korrektur-Code zuerst die Verteilung kennt, korrigiert gezielter.

qpdf und pikepdf im Vergleich: wann was?
Aspekt qpdf (CLI/C++) pikepdf (Python)
Schnelle Inspektion Ja, --qdf , --json=2 , --check in Sekunden. Möglich, aber Overhead durch Skript-Setup.
Skripting / Pipelines Per Shell-Skript, aber begrenzte Logik. Volle Python-Logik: Bedingungen, Tests, Schleifen.
Objekt-Editor Nur grobe Operationen (Seiten extrahieren, mergen). Dictionaries, Arrays, Strings gezielt verändern.
Lernkurve Kommandozeilen-Kenntnisse reichen. Python-Grundkenntnisse plus PDF-Modell.
Performance Sehr schnell, native C++-Implementierung. Schnell, gleicher qpdf-Kern, Python-Wrapper-Overhead.

Grenzen: was qpdf und pikepdf nicht leisten

Beide Werkzeuge sind hervorragend, wenn die Struktur eines PDF inspiziert oder gezielt korrigiert werden soll. Was sie nicht tun, ist genauso wichtig:

  • Sie erzeugen keine semantische Bewertung. Ob ein Alternativtext inhaltlich passt, weiß weder qpdf noch pikepdf. Das bleibt menschliche Beurteilung oder die Aufgabe eines Validators wie veraPDF, der wenigstens prüfen kann, ob ein Alt-Text vorhanden ist.
  • Sie machen kein OCR. Ein gescanntes PDF ohne Text-Layer bleibt für beide ein Bild. Für OCR brauchst du andere Werkzeuge (Tesseract, Adobe Acrobat, ocrmypdf).
  • Sie ersetzen kein PDF/UA-Audit. Sie helfen, konkrete Befunde aus einem Audit gezielt zu reparieren, aber sie ersetzen die Prüfung selbst nicht. Die Quelle der Wahrheit bleibt die ISO-Norm und ihre Validator-Implementierungen.
Mythen-Prüfung

Drei Annahmen, und warum sie nicht stimmen

Mythos 1: „qpdf repariert kaputte PDFs." Nur teilweise. qpdf kann eine PDF-Datei mit beschädigter Cross-Reference- Tabelle rekonstruieren. Das ist das, was qpdf --check meldet und was eine spätere Neuausgabe behebt. Inhaltliche Probleme, fehlende Tags oder falsche Lese-Reihenfolgen sind keine Strukturkorruption und werden nicht „repariert". Sie müssen gezielt korrigiert werden.

Mythos 2: „pikepdf ist nur ein Python-Wrapper, also langsam." Falsch. pikepdf bindet die qpdf-C++-Bibliothek über pybind11 ein: die rechenintensiven Operationen laufen nativ. Der Python-Code steuert nur die Logik, nicht die PDF-Verarbeitung selbst. In der Praxis verarbeitet pikepdf auch große Dokumente flüssig.

Mythos 3: „Was Adobe Acrobat anzeigt, ist die Wahrheit über das PDF." Vorsicht. Acrobat interpretiert das PDF nach eigenen Regeln und repariert beim Öffnen still einige Inkonsistenzen. Wer mit qpdf oder pikepdf in die Roh-Datei schaut, sieht den tatsächlichen Zustand, der manchmal von dem abweicht, was Acrobat als Tag-Baum darstellt.