Skip to content

Leistung

PDF Oxide v0.3.11 liefert 0,8ms durchschnittliche Textextraktion in Python über einen Korpus von 3.830 PDFs — 5× schneller als PyMuPDF und 15× schneller als pypdf, mit 100% Erfolgsrate bei gültigen PDFs.

Benchmark-Ergebnisse

Korpus: 3.830 PDFs

Drei unabhängige öffentliche Testsuiten kombiniert:

Suite PDFs Quelle
veraPDF 2.907 PDF/A-Konformitätstest-Korpus
Mozilla pdf.js 897 Browser-PDF-Rendering-Testsuite
SafeDocs 26 DARPA SafeDocs Korpus fehlerhafter PDFs

Warum dieser Korpus zuverlässig ist

Dies sind keine handverlesenen PDFs. Jede Suite ist ein etablierter, peer-reviewter Testkorpus, der von Standardisierungsgremien oder großen Open-Source-Projekten gepflegt wird:

  • veraPDF ist der offizielle PDF/A-Konformitätsvalidator, der seit über 10 Jahren von der PDF-Standardisierungsgemeinschaft verwendet wird. Seine 2.907 Testdateien sind atomar — jede testet genau ein PDF-Spezifikationsmerkmal — und decken alle PDF/A-Versionen (1A/1B, 2A/2B/2U, 3A/3B/3U, 4/4E/4F), PDF/UA-Barrierefreiheit (UA1, UA2) sowie ISO 32000-1 (PDF 1.7) und ISO 32000-2 (PDF 2.0) ab. Lizenziert unter CC BY 4.0.

  • Mozilla pdf.js betreibt das PDF-Rendering in Firefox und verarbeitet jährlich Milliarden von PDFs. Seine 897 Testdateien decken praxisnahe Rendering-Grenzfälle ab: komplexe mehrseitige Dokumente, Anmerkungentypen (Randstile, Hervorhebungen, Einfügemarken, Dateianhänge), Formular-Widgets, ungewöhnliche Schriftkodierungen, große Stresstest-Dokumente und Content-Stream-Grenzfälle. 7 Dateien sind absichtlich beschädigt, um die korrekte Fehlererkennung zu testen.

  • DARPA SafeDocs ist ein vom US-Staat finanziertes Sicherheitsforschungsprogramm, das sich auf Parser-Robustheit konzentriert. Seine 26 Dateien zielen auf die schwierigsten Grenzfälle ab: Content-Stream-Zyklen in Type3-Schriften, doppelte Startxref-Trailer, kompaktierte PDF-Syntax, Dialektvariationen, Inline-Bild-Grenzfälle, rekursive Schriftverschachtelung und verschlüsselte PDFs mit Unicode-Passwörtern (einschließlich UTF-16 LE). Diese Dateien sind darauf ausgelegt, anfällige Parser zum Absturz zu bringen, zu blockieren oder auszunutzen.

Was dieser Korpus abdeckt

  • Alle wichtigen PDF-Versionen: PDF 1.0 bis PDF 2.0
  • Verschlüsselung und Passwörter: AES-256, RC4, Unicode-Passwörter, UTF-16-LE-Kodierung
  • Sicherheitsgrenzfälle: Rekursive Strukturen, Content-Stream-Zyklen, fehlerhafte Trailer, durch Fuzzing erzeugte Korruption
  • Schriftvielfalt: TrueType, CIDFont, Type1, Type3, CJK-Kodierungen, eingebettete Untergruppen
  • Dokumentkomplexität: Von einseitigen Fixtures bis zu Dokumenten mit über 10.000 Seiten, Inline-Bilder, verschachtelte Form XObjects
  • Korrekte Ablehnung: 7 absichtlich fehlerhafte Dateien (fehlende PDF-Header, ungültige Xref-Streams) — eine Bibliothek, die diese „parst", ist weniger sicher, nicht zuverlässiger

Von den 3.830 Dateien sind 3.823 gültige PDFs. Die 7 ungültigen Dateien sind Test-Fixtures für die Fehlerbehandlung — PDF Oxide lehnt alle 7 korrekt ab.

Vergleich von Python-Bibliotheken

Durchschnittliche Textextraktionszeit pro PDF über den vollständigen Korpus von 3.830 PDFs:

Bibliothek Durchschnitt p99 Erfolgsrate Lizenz
PDF Oxide 0,8ms 9ms 100% MIT
PyMuPDF 4,6ms 28ms 99,3% AGPL-3.0
pypdfium2 4,1ms 42ms 99,2% Apache-2.0
pymupdf4llm 55,5ms 280ms 99,1% AGPL-3.0
pdftext 7,3ms 82ms 99,0% GPL-3.0
pdfminer 16,8ms 124ms 98,8% MIT
pdfplumber 23,2ms 189ms 98,8% MIT
markitdown 108,8ms 378ms 98,6% MIT
pypdf 12,1ms 97ms 98,4% BSD-3

PDF Oxide ist die schnellste verfügbare Python-PDF-Bibliothek. Im Gegensatz zu PyMuPDF verwendet sie die MIT-Lizenz — keine AGPL-Einschränkungen für kommerzielle Nutzung.

Vergleich von Rust-Bibliotheken

Bibliothek Durchschnitt p99 Erfolgsrate Textextraktion
PDF Oxide 0,8ms 9ms 100% Integriert, produktionsreif
oxidize_pdf 13,5ms 11ms 99,1% Grundlegend
unpdf 2,8ms 10ms 95,1% Grundlegend
pdf_extract 4,08ms 37ms 91,5% Grundlegend
lopdf 0,3ms 2ms 80,2% Keine integrierte Extraktion

lopdf ist bei den PDFs, die es parsen kann, schneller, scheitert aber bei 20% des Korpus. pdf_oxide ist das einzige Rust-Crate, das 100% Zuverlässigkeit mit integrierter Textextraktion vereint. Beachten Sie, dass lopdf keine Textextraktion bietet — Sie müssen Schriftdekodierung und Abstandsanalyse selbst implementieren.

Textqualität

PDF Oxide erreicht 99,5% Textparität im Vergleich zu PyMuPDF und pypdfium2 über den gesamten Korpus. Die Qualität wurde durch zeichenweisen Vergleich der extrahierten Textausgabe über alle 3.823 gültigen PDFs gemessen.

Aufschlüsselung nach Korpus

Korpus PDFs PDF Oxide Durchschnitt pypdfium2 Durchschnitt PyMuPDF Durchschnitt
veraPDF 2.907 0,7ms 3,6ms 4,1ms
Mozilla pdf.js 897 1,1ms 5,8ms 6,2ms
SafeDocs 26 0,9ms 4,0ms 4,3ms

Optimierungshistorie: v0.3.5 → v0.3.8

v0.3.8 beseitigte zwei kritische O(n)-Engpässe, die den Durchschnitt von 23,3ms auf 0,8ms (Python) über denselben Korpus senkten.

1. Bulk-Seitenbaum-Cache

Vorher: get_page() durchlief den Seitenbaum von der Wurzel für jede nicht gecachte Seite. Bei sequentieller Extraktion aller Seiten war dies O(n) pro Seite und O(n²) insgesamt.

Nachher: Beim ersten Seitenzugriff wird der gesamte Seitenbaum einmal durchlaufen und alle Seiten werden in einer HashMap<usize, Object> gecacht. Jeder weitere Zugriff ist O(1).

Dies ist die Korrektur, die ein 10.000-seitiges PDF von 55 Sekunden auf 332 Millisekunden brachte.

2. Scan-for-Object Offset-Cache

Vorher: Wenn Objekte in der Xref-Tabelle fehlten, las scan_for_object() die gesamte PDF-Datei für jedes fehlende Objekt. Getaggte PDFs mit Hunderten von Strukturbaum-Elementen, die nicht im Xref waren, lösten Hunderte vollständiger Dateilesungen aus.

Nachher: Die Datei wird einmal gescannt und alle Objekt-Offsets werden in einer HashMap gecacht. Nachfolgende Abfragen sind O(1).

3. Einpass-Textextraktion

Vorher: extract_spans() führte zwei Durchgänge über den Seiteninhalt durch — zuerst zur Klassifizierung des Dokumenttyps (akademisch, Zeitung, Formular usw.), dann zur Textextraktion.

Nachher: Der Klassifizierungsdurchgang wurde vollständig eliminiert. Adaptive schriftbewusste Schwellenwerte liefern nun gleiche oder bessere Ergebnisse in einem einzigen Durchgang.

4. Content-Stream-Vorabzuweisung

Vorher: parse_content_stream() baute den Operator-Vec mit Standardkapazität auf, was bei großen Content Streams wiederholte Neuzuweisungen verursachte.

Nachher: Der Vec wird basierend auf der Stream-Größe (data.len() / 20) vorab zugewiesen, was etwa einen Operator pro 20 Bytes schätzt.

Methodik

Alle Benchmarks verwenden dieselbe Methodik:

  1. Jede Bibliothek verarbeitet alle 3.830 PDFs mit Python-Multiprocessing (ein PDF pro Prozess)
  2. 60-Sekunden-Timeout pro PDF — jedes PDF, das dies überschreitet, wird als Fehler gezählt
  3. Extrahierter Text wird pro Bibliothek auf der Festplatte für Qualitätsvergleiche gespeichert
  4. Die Wanduhrzeit wird vom Öffnen der Datei bis zur endgültigen Textextraktion gemessen
  5. Keine Aufwärmdurchläufe, kein Caching zwischen Dateien
  6. Ein Thread pro PDF

Der Benchmark-Harness führt alle 18 Bibliotheken (3 Rust, 15 Python) auf derselben Maschine, demselben Korpus und unter denselben Bedingungen aus.

Benchmarks reproduzieren

Die öffentlichen Testkorpora sind frei verfügbar:

Führen Sie die Verifizierung aus:

cargo run --release --example verify_corpus -- \
    /path/to/veraPDF-corpus \
    /path/to/pdfjs-test \
    /path/to/safedocs \
    --csv results.csv

Leistungsmerkmale

Wobei PDF Oxide schnell ist

  • Textextraktion: Das primäre Optimierungsziel. Sub-Millisekunde für typische Dokumente.
  • Sequentielle Mehrseitenextraktion: Der Seitenbaum-Cache macht die Extraktion aller Seiten eines großen Dokuments nahezu so schnell wie die Extraktion einer einzigen.
  • Getaggte PDFs: Strukturbaum-Traversierung und Objektauflösung sind jetzt gecacht.
  • Fehlerhafte PDFs: Tolerantes Parsing mit Fallback-Strategien vermeidet teure Wiederholungsversuche.

Was linear skaliert

  • Seitenzahl: Jede Seite wird unabhängig verarbeitet. 100 Seiten dauern ungefähr 100× so lang wie eine Seite.
  • Content-Stream-Größe: Das Parsen von Operatoren ist linear zur Stream-Länge.
  • Bildextraktion: Proportional zur Anzahl und Größe der Bilder.

Wann langsamere Ergebnisse zu erwarten sind

  • Gescannte PDFs mit OCR: OCR-Verarbeitung (falls aktiviert) ist erheblich langsamer als Textextraktion.
  • Rendering: Seitenrendering zu Bildern hängt von der Inhaltskomplexität und dem Ziel-DPI ab.
  • Stark verschlüsselte PDFs: AES-256-Entschlüsselung verursacht Overhead pro Stream.
  • PDFs mit Tausenden von Schriften: Schrift-Parsing wird pro Dokument gecacht, aber das initiale Parsing skaliert mit der Schriftanzahl.

Nächste Schritte