PDF Oxide vs. lopdf
lopdf ist ein Low-Level-Rust-Crate für die direkte Manipulation von PDF-Objekten. PDF Oxide ist eine High-Level-Bibliothek mit integrierter Textextraktion, Erstellung und Bearbeitung. Beide zielen auf grundlegend unterschiedliche Anwendungsfälle ab.
Wesentliche Unterschiede
Abstraktionsebene. lopdf liefert rohe PDF-Objekte – Dictionaries, Streams und Querverweistabellen. Es gibt keine Textextraktion, keine Schriftdekodierung, keinen Bildexport. PDF Oxide stellt zweckgebundene Methoden bereit: extract_text(), extract_images(), to_markdown().
Zuverlässigkeit. lopdf scheitert beim Parsen von 20 % des Testkorpus aus 3.830 PDFs. Von den PDFs, die es parsen kann, erzeugen 57 % leere Ausgaben, weil lopdf keine Textextraktion besitzt – man erhält die Objekte, aber keinen Text. PDF Oxide besteht zu 100 %.
Geschwindigkeit bei parsbaren PDFs. Beim reinen Parsen von Objekten ist lopdf schneller: 0,3 ms im Mittel gegenüber 0,8 ms bei PDF Oxide. Aber lopdf leistet keinerlei Textextraktion – Schriftdekodierung, CMap-Auflösung, Abstandsanalyse und Lesereihenfolge müsstest du selbst aufbauen.
Kurzvergleich
| PDF Oxide | lopdf | |
|---|---|---|
| API-Ebene | High-Level | Low-Level |
| Textextraktion | Integriert (produktionsreif) | Keine |
| Erfolgsquote (3.830 PDFs) | 100 % | 80,2 % |
| Mittlere Parsing-Zeit | 0,8 ms | 0,3 ms |
| Bildextraktion | Integriert | Manuell (rohe Streams) |
| Formularfelder | Lesen + Schreiben | Manuell (rohe Dictionaries) |
| PDF-Erstellung | Ja (Markdown/HTML) | Ja (rohe Objekte) |
| Markdown-/HTML-Ausgabe | Ja | Nein |
| Verschlüsselung | Lesen + Schreiben | Nein |
| Rendering | Ja | Nein |
| PDF/A-Validierung | Ja | Nein |
| Lizenz | MIT | MIT |
Was lopdf nicht kann
lopdf gewährt Zugriff auf PDF-Objekte, doch die Textextraktion erfordert, diese Objekte gemäß der PDF-Spezifikation zu interpretieren. Folgendes müsstest du selbst aufbauen:
- Parsen des Content-Streams – PostScript-ähnliche Operatoren parsen (Tj, TJ, Tm, Tf usw.)
- Schriftauflösung – /Font-Ressourcen nachschlagen, indirekte Verweise auflösen
- CMap-/ToUnicode-Dekodierung – Glyph-IDs in Unicode-Zeichen umwandeln
- Abstände über Schriftmetriken – Zeichenbreiten aus Schriftdeskriptoren berechnen
- Textmatrix-Transformationen – die Operatoren Tm, Td, T* anwenden, um Text zu positionieren
- Lesereihenfolge – die richtige Reihenfolge für mehrspaltige Layouts bestimmen
- Ligatur-Rekonstruktion – die Ligaturen fi, fl, ffi behandeln
- CJK-Kodierung – chinesische, japanische und koreanische Textkodierungen dekodieren
Das sind Tausende Zeilen Code und tiefes Wissen über ISO 32000. PDF Oxide erledigt all das intern.
Code im direkten Vergleich
Textextraktion
PDF Oxide:
use pdf_oxide::PdfDocument;
let mut doc = PdfDocument::open("report.pdf")?;
let text = doc.extract_text(0)?;
println!("{}", text);
lopdf:
use lopdf::Document;
let doc = Document::load("report.pdf")?;
// lopdf does not provide text extraction.
// You get access to PDF objects only:
let page_id = doc.page_iter().next().unwrap();
let page = doc.get_dictionary(page_id)?;
let contents = page.get("Contents")?;
let stream = doc.get_object(contents.as_reference()?)?;
// To get actual text, you must:
// 1. Parse content stream operators
// 2. Resolve font references from /Resources
// 3. Decode CMap/ToUnicode mappings
// 4. Apply text matrix transformations
// 5. Handle encoding differences
// ... (hundreds to thousands of lines of code)
PDF-Erstellung
PDF Oxide:
use pdf_oxide::api::Pdf;
let pdf = Pdf::from_markdown("# Report\n\n| Q1 | Q2 |\n|---|---|\n| $1M | $2M |")?;
pdf.save("report.pdf")?;
lopdf:
use lopdf::{Document, Object, Stream, dictionary};
let mut doc = Document::with_version("1.5");
// Create font dictionary
let font_id = doc.add_object(dictionary! {
"Type" => "Font",
"Subtype" => "Type1",
"BaseFont" => "Helvetica",
});
// Create resources
let resources_id = doc.add_object(dictionary! {
"Font" => dictionary! { "F1" => font_id },
});
// Create content stream (raw PostScript operators)
let content = Stream::new(
dictionary! {},
b"BT /F1 12 Tf 72 720 Td (Hello World) Tj ET".to_vec(),
);
let content_id = doc.add_object(content);
// Create page
let page_id = doc.add_object(dictionary! {
"Type" => "Page",
"MediaBox" => vec![0.into(), 0.into(), 612.into(), 792.into()],
"Contents" => content_id,
"Resources" => resources_id,
});
// Wire up page tree
let pages_id = doc.add_object(dictionary! {
"Type" => "Pages",
"Kids" => vec![page_id.into()],
"Count" => 1,
});
doc.add_object(dictionary! {
"Type" => "Catalog",
"Pages" => pages_id,
});
doc.save("report.pdf")?;
Verschlüsselte PDFs
PDF Oxide:
use pdf_oxide::PdfDocument;
let doc = PdfDocument::open_with_password("encrypted.pdf", "secret")?;
let text = doc.extract_text(0)?;
println!("{}", text);
lopdf:
// lopdf does not support encrypted PDFs.
// Loading an encrypted PDF will fail or produce undecrypted streams.
Zuverlässigkeitsvergleich
| Kennzahl | PDF Oxide | lopdf |
|---|---|---|
| Erfolgreich geparste PDFs | 3.823 / 3.823 (100 %) | 3.071 / 3.823 (80,2 %) |
| PDFs mit Textausgabe | 3.823 / 3.823 | ~1.320 / 3.823 (geschätzt) |
| Unterstützung verschlüsselter PDFs | Ja | Nein |
| Wiederherstellung fehlerhafter PDFs | Ja | Nein |
Die Erfolgsquote von 80,2 % bei lopdf bedeutet, dass es bei etwa 1 von 5 PDFs scheitert. Die Fehler treten bei verschlüsselten Dokumenten, PDFs mit nicht standardkonformen xref-Tabellen und Dokumenten mit Querverweis-Streams auf. PDF Oxide bewältigt all dies durch tolerantes Parsen und Fallback-Strategien.
Wann was verwenden
Wähle PDF Oxide, wenn:
- Du Textextraktion, Bildextraktion oder eine beliebige Operation auf Inhaltsebene benötigst
- Du ein einziges Crate für Lesen + Schreiben + Erstellen möchtest
- Du alle PDFs zuverlässig verarbeiten musst (verschlüsselt, fehlerhaft, komplex)
- Du Markdown-/HTML-Ausgabe, Rendering oder OCR benötigst
- Du eine Konformitätsprüfung (PDF/A, PDF/X, PDF/UA) brauchst
Wähle lopdf, wenn:
- Du direkten Zugriff auf PDF-Objekte für eigene Verarbeitung benötigst
- Du ein spezialisiertes PDF-Werkzeug baust, das auf Objektebene arbeitet
- Du Dokumente durch direkte Manipulation von Objektbäumen zusammenführen musst
- Deine PDFs einfach und wohlgeformt sind (nicht verschlüsselt, standardkonforme xref-Tabellen)
Beide kombinieren:
Nutze PDF Oxide für High-Level-Operationen und lopdf für Sonderfälle, die Zugriff auf rohe Objekte erfordern:
[dependencies]
pdf_oxide = "0.3"
lopdf = "0.32"
Verwandte Seiten
- Performance-Benchmarks – vollständige Korpus-Ergebnisse
- vs. Rust-PDF-Bibliotheken – alle Rust-Crates im Vergleich
- Erste Schritte mit Rust – Installation und erste Extraktion