yolowpdf: a PDF-to-Markdown parser written from scratch in Rust — plus its own OCR engine
PDF parsing in Rust usually means wrapping a C library. yolowpdf reads the file format itself: no Poppler, no MuPDF, no native PDF library at all.
It is the PDF engine extracted from PageSift (from the 1.2.4 tree), now an independent MIT-licensed workspace. It is also the second spin-off in a week, after yolow64.
Why it exists
PageSift needed to turn PDFs found in the wild into clean Markdown without installing a native PDF stack on every machine. Wild PDFs are not clean: broken xref tables, object streams, encrypted streams, CID fonts with no ToUnicode map, multi-column layouts, tables, inline formulas, images, and scanned pages with no text layer at all.
Handling all of that grew into a standalone reader: file structure and damaged-file repair, fonts (Type1, TrueType, CFF, CID, predefined CMaps, CJK collections without ToUnicode), layout reconstruction (paragraphs, headings, reading order, headers/footers, lists), ruled and borderless tables, inline math rebuilt as LaTeX from glyph metrics, image extraction (JPEG, JPEG 2000, JBIG2, CCITT, PNG, TIFF, WebP) — and a PageOcr trait for scanned pages.
The OCR side became a second crate: yolowpdf-ocr implements PP-OCRv6 detection and recognition, with optional document-layout and formula models, on CPU or an NVIDIA GPU, with automatic fallback to CPU and a reported reason when the GPU cannot start. The core crate never depends on a model runtime; OCR is opt-in.
The API is deliberately small:
let bytes = std::fs::read("document.pdf")?;
let doc = yolowpdf::extract(&bytes)?;
println!("{}", doc.markdown);
println!("pages: {}", doc.pages.len());
println!("scanned: {}", doc.scanned);
extract_with adds limits, image options and the OCR engine. Errors are Malformed, Encrypted, TooLarge or Timeout — and a parser panic is caught and returned as an error instead of taking the caller down.
Benchmarks (exploratory, with the caveats kept)
Runs on public olmOCR-bench data, one machine (i7-10700, 15 GB RAM, GTX 1070). These are exploratory runs, not certified official scores; tools differ in features and conditions, and the full methodology — actual worker counts, caps, raw results — is in the repo's benchmarks/ report.
Born-digital pages (1,269 pages):
| Tool | Completed | Pages/s | p50 | Peak MB/worker | Score |
|---|---|---|---|---|---|
| yolowpdf | 1269/1269 | 1,900 | 3.2 ms | 24 | 0.592 |
| pymupdf4llm | 1213/1269 | 6.56 | 845.6 ms | 600 | 0.489 |
| pypdf | 1213/1269 | 79.4 | 73.9 ms | 186 | 0.385 |
| MarkItDown | 1204/1269 | 13.6 | 172.8 ms | 1,171 | 0.373 |
On the pdf.js corpus of hard files (1,089 files), yolowpdf finished 830 files at 1,663 files/s; pymupdf4llm finished slightly more (841) at 1.31 files/s under different I/O conditions. That cell is in the README too — a fast parse is not the same as understanding a difficult page, and the README says so itself.
For scanned pages, yolowpdf-ocr (GPU, text only) completed all 134 olmOCR-bench scan pages at 2.245 pages/s; adding layout and formula models raised the score to 0.5428.
Install
On crates.io:
[dependencies]
yolowpdf = "0.1"
# Optional OCR:
yolowpdf-ocr = "0.1"
Rust 1.89+, edition 2024, MIT licensed. Models for OCR are downloaded by the caller (pinned revisions and SHA-256 values are listed in the source); nothing is bundled.
Repo: https://github.com/YOLOW92/yolowpdf
If you feed PDFs into LLM pipelines, I'd like to hear what breaks. Hard files especially welcome.
Top comments (0)