Skip to content

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:

  1. Parsen des Content-Streams – PostScript-ähnliche Operatoren parsen (Tj, TJ, Tm, Tf usw.)
  2. Schriftauflösung – /Font-Ressourcen nachschlagen, indirekte Verweise auflösen
  3. CMap-/ToUnicode-Dekodierung – Glyph-IDs in Unicode-Zeichen umwandeln
  4. Abstände über Schriftmetriken – Zeichenbreiten aus Schriftdeskriptoren berechnen
  5. Textmatrix-Transformationen – die Operatoren Tm, Td, T* anwenden, um Text zu positionieren
  6. Lesereihenfolge – die richtige Reihenfolge für mehrspaltige Layouts bestimmen
  7. Ligatur-Rekonstruktion – die Ligaturen fi, fl, ffi behandeln
  8. 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