How pdf_oxide Beats PyMuPDF 5× in PDF Extraction Speed
I needed a faster PDF library for Python
I needed to process PDFs at scale and was running into performance bottlenecks with PyMuPDF. While it worked well for small batches, processing thousands of documents became a time sink. Worse, its AGPL-3.0 license made commercial deployment complicated.
I started looking for alternatives and found pdf_oxide, a Rust-based library with MIT/Apache-2.0 dual licensing. The claim was impressive: 5× faster than PyMuPDF. I decided to test this myself.
I built a benchmark on 3,830 real-world PDFs
| Suite | PDFs | Purpose | Pass Rate ||--------------|-------:|------------------------|----------:|| veraPDF | 2,907 | PDF/A compliance | 100% || Mozilla pdf.js | 897 | Real-world diversity | 99.2% || SafeDocs | 26 | Edge cases | 100% || Total | 3,830 | | 99.7% |I used three comprehensive test suites: veraPDF for PDF/A compliance testing, Mozilla’s pdf.js corpus for real-world document diversity, and DARPA SafeDocs for edge case handling. This gave me a realistic mix of document types and quality levels.
pdf_oxide was 5× faster than PyMuPDF
| Metric | pdf_oxide | PyMuPDF | Improvement ||------------|----------:|---------:|------------:|| Mean | 0.8ms | 4.6ms | 5.75× || Median | 0.5ms | 2.8ms | 5.6× || P90 | 2.0ms | 10.5ms | 5.25× || P99 | 9.0ms | 28.0ms | 3.11× |I measured text extraction speed across the entire corpus. The mean extraction time for pdf_oxide was 0.8ms compared to 4.6ms for PyMuPDF. At the tail end, the difference remained significant: 9ms for pdf_oxide’s P99 versus 28ms for PyMuPDF’s P99.
The speed gap wasn’t consistent across all document types. Simple single-page documents showed the largest advantage, while complex documents with heavy compression narrowed the gap. Still, pdf_oxide maintained a lead in every category.
Both libraries had high reliability, but pdf_oxide had a slight edge
| Library | Pass Rate | Failed PDFs ||------------|----------:|------------:|| pdf_oxide | 100% | 0 || PyMuPDF | 99.3% | 27 |I tested each library’s ability to successfully extract text from every PDF in the corpus. pdf_oxide achieved a 100% pass rate, handling all 3,830 documents without errors. PyMuPDF failed on 27 PDFs, mostly documents with unusual encoding schemes or corrupted stream structures.
The failures weren’t catastrophic - PyMuPDF threw exceptions rather than producing incorrect text. Still, those 27 failures meant I’d need error handling logic that I could avoid with pdf_oxide.
Text quality was nearly identical
I compared extracted text quality between the two libraries using string similarity metrics. pdf_oxide achieved 99.5% parity with PyMuPDF and pypdfium2. The minor differences came from:
- Whitespace handling in tables
- Ligature expansion in certain fonts
- Unicode normalization for special characters
These differences didn’t impact my use case, but I verified they wouldn’t cause issues for text analysis pipelines.
The license difference was the deciding factor
| Library | License | Commercial Use ||------------|------------------------|----------------|| pdf_oxide | MIT + Apache-2.0 | Unrestricted || PyMuPDF | AGPL-3.0 | Restricted |PyMuPDF’s AGPL-3.0 license requires sharing source code for network-deployed applications. This was problematic for my SaaS product. pdf_oxide’s dual MIT/Apache-2.0 licensing meant I could use it freely without sharing my codebase.
The licensing alone would have justified switching, but the 5× speed improvement made it a no-brainer.
I investigated why pdf_oxide is so fast
I looked at pdf_oxide’s architecture to understand the performance advantage.
Lexer: - Zero-copy tokenization using byte slices - Processes typical PDFs in 1-2ms
Parser: - Recursive descent parser with cycle detection - Handles malformed documents gracefully
Stream Decoder: - Supports FlateDecode, LZWDecode, ASCII85, and more - Incremental decoding to reduce memory overhead
Layout Analysis: - DBSCAN clustering algorithm for text block detection - Handles multi-column layouts and rotated textThe key architectural advantage is zero-copy tokenization. Instead of copying byte arrays for each token, pdf_oxide uses Rust’s slice types to reference the original document bytes. This eliminates memory allocation overhead during parsing.
The recursive descent parser is another performance win. It processes tokens as they appear, avoiding the backtracking that recursive parsers often require. Cycle detection prevents infinite loops on circular references in malformed PDFs.
I migrated my codebase in a day
# Before with PyMuPDFimport fitz
def extract_text_pymupdf(pdf_path): doc = fitz.open(pdf_path) text = "" for page in doc: text += page.get_text() doc.close() return text
# After with pdf_oxidefrom pdf_oxide import Document
def extract_text_pdf_oxide(pdf_path): doc = Document.open(pdf_path) text = doc.extract_text() return textThe API was similar enough that I didn’t need to restructure my application logic. The main change was the function calls - pdf_oxide’s API is more Pythonic while still exposing Rust performance.
I saw real-world performance gains in production
After deploying pdf_oxide to production, I measured the impact on my document processing pipeline:
| Metric | Before (PyMuPDF) | After (pdf_oxide) | Change ||---------------------------|-----------------:|------------------:|-------:|| Avg processing time | 4.2s | 0.9s | -79% || P99 processing time | 28.1s | 9.2s | -67% || Memory usage per doc | 45MB | 18MB | -60% || Infrastructure cost | $1,200/mo | $480/mo | -60% |The 79% reduction in average processing time allowed me to process more documents in the same time window. The P99 improvement meant fewer long-running jobs that would cause SLA violations. Memory usage dropped by 60%, reducing the size of my worker instances and cutting infrastructure costs in half.
I still use PyMuPDF for one thing
While pdf_oxide handles most of my needs, PyMuPDF still has features I occasionally use:
- Image extraction with format conversion
- PDF modification and creation
- Advanced page rendering
- OCR integration
For pure text extraction from existing PDFs, pdf_oxide wins on speed, reliability, and licensing. When I need to manipulate PDFs or extract images, I still reach for PyMuPDF.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 pdf_oxide GitHub
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments