Open Source
Explore the latest AI open-source projects from GitHub and HuggingFace.
Explore the latest AI open-source projects from GitHub and HuggingFace.
pdf-inspector is a Rust library that answers one question fast: does this PDF actually need OCR? Built by Firecrawl for its own document pipeline, it classifies a PDF as text-based, scanned, image-based or mixed in roughly 10–50 ms, then extracts position-aware text and converts it to clean Markdown — all locally, with no ML models and no external services.
The repository was created on 6 February 2026 and sits at roughly 11,550 stars and 780 forks, with commits through 5 August and 10 contributors. It is MIT-licensed and ships on crates.io, npm, and PyPI, plus a browser WebAssembly build.
Document pipelines that feed LLMs tend to have one expensive default: send every PDF to an OCR service. That costs 2–10 seconds and real money per document. Firecrawl's observation is that roughly 54% of PDFs don't need it — reports, papers, invoices and legal filings usually carry a perfectly good text layer already.
The classifier is deliberately cheap. It parses the xref table and page tree without a full object load, then looks for Tj/TJ text operators and Do image operators in content streams across sampled pages. That detects 300+ page PDFs in milliseconds. The result is not a single verdict but a pages_needing_ocr list, which enables per-page routing instead of an all-or-nothing decision on the whole document.
Four scan strategies trade accuracy against speed:
| Strategy | Behavior | Best for |
|---|---|---|
EarlyExit (default) | Stops on first non-text page | Pipelines routing text PDFs to fast extraction |
Full | Scans every page, no early exit | Accurate Mixed vs Scanned classification |
Sample(n) | Samples n evenly distributed pages | Very large PDFs where speed dominates |
Pages(vec) | Scans specific page numbers | When the caller already knows where to look |
The resulting flow is: classify in ~20 ms, and if it is text-based with high confidence, extract locally in ~150 ms. Otherwise pay for OCR. The document is loaded once and shared between detection and extraction, so choosing to extract costs no redundant parse.
This is not a text dump. The extractor walks PDF operators into positioned TextItems with font metadata, then runs column detection, line grouping and reading-order resolution before Markdown conversion. Headings come from font-size tiers relative to body text with 0.5pt clustering; code blocks from monospace font detection (Courier, Consolas, Menlo, JetBrains Mono); bold and italic from font-name patterns.
Table detection runs dual-mode — rectangle-based detection from the PDF's own drawing operations, plus heuristic detection from text alignment — which is what lets it handle financial tables, footnotes and tables that continue across pages. Multi-column newspaper layouts, RTL text, CID fonts via ToUnicode CMap decoding, hyphenation rejoining, drop caps, dot-leader collapsing and page-number filtering are all handled explicitly.
It also flags broken font encodings, so a caller can fall back to OCR when the text layer exists but is garbage — the failure mode that silently corrupts naive extraction pipelines.
On the opendataloader-bench corpus of 200 PDFs with OCR disabled, refreshed 31 July 2026 on an M4 Pro:
| Engine | Overall | Reading Order | Tables | Headings | Speed |
|---|---|---|---|---|---|
| pdf-inspector | 0.875 | 0.915 | 0.814 | 0.788 | 0.470s |
| liteparse | 0.873 | 0.913 | 0.693 | 0.811 | 0.750s |
| opendataloader | 0.831 | 0.902 | 0.489 | 0.739 | 2.569s |
| pymupdf4llm | 0.735 | 0.886 | 0.401 | 0.424 | 17.117s |
| markitdown | 0.589 | 0.844 | 0.273 | 0.000 | 16.165s |
The table margin is the real gap — 0.814 against 0.693 for the nearest competitor — and the 36× speed difference against pymupdf4llm is the kind of number that changes pipeline architecture rather than just a config value. Per-document predictions and evaluator output are published in a reproducible results branch, and a paired benchmark harness ships for comparing two local builds against the same corpus revision.
The benchmark is the vendor's own. Firecrawl ran the comparison, chose the corpus, and picked which engines appear. The methodology is unusually well documented — versions pinned, median of five runs, warm-up excluded, raw output published — but it is still a self-published result and the near-tie with liteparse on overall score (0.875 vs 0.873) is closer than the framing suggests.
It deliberately does not do OCR. This is a router and a fast path, not a complete document solution. Anyone with a corpus of scans still needs the expensive service; pdf-inspector only tells you which documents to send there.
Heading detection is its weakest column. At 0.788 it trails liteparse's 0.811, and font-size-tier heuristics will misread documents that signal structure by weight or spacing rather than size.
Structure detection is heuristic throughout. Code blocks inferred from font names, lists from bullet-character prefixes, tables partly from text alignment — these work well on conventional documents and will degrade on unusual typography. There is no model to fall back on when the heuristics miss.
78 open issues. The surface is broad — four language bindings, WebAssembly, two CLI tools — and the parsing edge cases in real-world PDFs are effectively unbounded.
The insight is an economic one rather than a research one: OCR is the expensive step in most document pipelines, and a large fraction of the documents entering those pipelines never needed it. Making the classification cheap enough to run unconditionally — 20 ms against 2–10 seconds — turns an unconditional cost into a conditional one.
Teams running document ingestion at scale for RAG or extraction should benchmark it against their own corpus, particularly if tables matter; the table score is where the daylight is. Teams whose documents are mostly scans will find it useful as a pre-filter and nothing more.