PDF Oxide - Fast PDF library in Rust with Python bindings (0.8ms, 100% pass rate)
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
lopdfgaps; 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
- Zero-Copy Parsing with
nom: PDF files can be massive. Usingnomcombinators allowed me to borrow tokens directly from the input buffer. No unnecessaryStringallocations for every object. - 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_oxidehandles CJK and custom-embedded fonts where others produce "mojibake." - 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/ETblocks. 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.