PDF Oxide - Fast PDF library in Rust with Python bindings (0.8ms, 100% pass rate)

98 points yfedoseev 24 comments

I’ve been building a PDF library in Rust from the ground up, and I wanted to share the journey and the benchmarks.

The Ecosystem Gap

I tried lopdf, pdf-rs, and pdf_extract, but none fit the bill for a high-reliability production pipeline.

  • lopdf: Great for low-level objects, but no native text extraction. It crashed on 20% of my test corpus.
  • pdf_extract: Inherits lopdf gaps; 91.5% pass rate (struggles with complex font encodings).
  • The Goal: A single crate that parses, extracts, creates, and renders reliably with a permissive license.

How Rust Made This Possible

  1. Zero-Copy Parsing with nom: PDF files can be massive. Using nom combinators allowed me to borrow tokens directly from the input buffer. No unnecessary String allocations for every object.
  2. The "Font Encoding" Nightmare: Resolving glyph IDs to Unicode is a multi-level fallback chain (ToUnicode → encoding differences → base encoding → CIDFont → Adobe Glyph List). The spec is ~40 pages of edge cases. Getting this right is why pdf_oxide handles CJK and custom-embedded fonts where others produce "mojibake."
  3. Layout Reconstruction: I implemented XY-Cut projection partitioning for multi-column layouts. It uses adaptive gap statistics based on font metrics to decide if a space is a character gap or a word boundary.

Performance: The v0.3.5 → v0.3.8 Optimization

I spent the last few weeks profiling, and the results were a massive jump:

  • Page Tree Caching: Sequential extraction of a 10,000-page document was $O(n^2)$ (~55 seconds). By implementing an Arc-wrapped bulk cache, it's now $O(1)$ (332ms).
  • Byte-level Scanning: Created a text-only content stream parser that skips all graphics operations outside of BT/ET blocks. This resulted in a 10–30x speedup on image-heavy pages.

Benchmarks (3,830 PDFs from veraPDF, Mozilla, & DARPA)

Library Mean Latency Pass Rate License
pdf_oxide (Rust) 0.8ms 100% MIT
PyMuPDF (C/C++) 4.6ms 99.3% AGPL-3.0
pypdf (Python) 12.1ms 98.4% BSD-3
pdf_extract (Rust) 4.08ms 91.5% MIT

Features

  • Extraction: Text, Markdown (heading detection), and Images.
  • Creation: PDF generation from Markdown, HTML, and images.
  • Advanced: OCR (PaddleOCR via ONNX), PDF/A validation, and Encryption.
  • Safety: Minimal unsafe.

Quick Start

Rust

// cargo add pdf_oxide
use pdf_oxide::PdfDocument;

let mut doc = PdfDocument::open("document.pdf")?;
for i in 0..doc.page_count()? {
    println!("{}", doc.extract_text(i)?);
}

GitHub: https://github.com/yfedoseev/pdf_oxide
Docs :https://oxide.fyi

I'd love to hear your feedback on the API. Also, if you have "cursed" PDFs that break every other library, please throw them at this
I'm currently hunting the last 17 edge cases in the SafeDocs corpus.