TopGit
GitHub Repo Review

pdf-inspector: Rust PDF Parser for Text & Markdown

firecrawl/pdf-inspector
PTopGit review image for firecrawl/pdf-inspector
Review by Topgit.dev for firecrawl/pdf-inspector, with GitHub repository stats and README context.
Quick verdict

pdf-inspector is a Rust library that classifies PDFs as text-based, scanned, image-based, or mixed, then extracts and converts the text-based ones to Markdown without touching OCR. Reach for it when you're building a document pipeline that needs to skip OCR costs for PDFs that already contain real text. Skip it if your PDFs are mostly scans — pdf-inspector detects that case correctly but doesn't extract from it.

Stars
★ 19.6k
Forks
⑂ 1.3k
Language
Rust
License
MIT
Topic
—
Updated
Oct 2026
Homepage
GitHub

Introducing pdf-inspector

pdf-inspector is a Rust library, built by Firecrawl, that tells text-based PDFs apart from scanned or image-based ones and turns the text-based pages into structured Markdown — headings, lists, tables, and links included. It ships official bindings for Python, Node.js, and browser WebAssembly, plus two CLI tools, pdf2md and detect-pdf, for one-off jobs from the terminal.

Key capabilities for PDF analysis

  • ✓Smart classification in ~10-50ms: samples content streams to label a PDF as TextBased, Scanned, ImageBased, or Mixed, with a 0.0-1.0 confidence score and per-page OCR routing.
  • ✓Position-aware text extraction that captures font info and X/Y coordinates for every text item.
  • ✓Markdown conversion that reconstructs headings (H1-H4 from font-size ratios), bullet/numbered/letter lists, monospace-detected code blocks, tables, and bold/italic runs.
  • ✓Dual-mode table detection: rectangle-based parsing of PDF drawing operators plus heuristic detection from text alignment, covering financial tables and continuation tables split across pages.
  • ✓CID font handling via ToUnicode CMap decoding for Type0/Identity-H fonts, across UTF-16BE, UTF-8, and Latin-1 encodings.
  • ✓Multi-column layout detection that reconstructs newspaper-style reading order and supports RTL text.
  • ✓Encoding-issue detection that flags broken font encodings so a caller knows to fall back to OCR instead of returning garbled text.
  • ✓A single document load shared between detection and extraction, so classifying and then extracting the same file doesn't re-parse it.
How this repository's GitHub stars have grown over time. Source: star-history.com.View the star history ↗

Practical applications and smart routing

  • •Pre-filtering a document ingestion pipeline: classify every incoming PDF first, extract text-based ones locally, and route only the scanned or image-based ones to an OCR service.
  • •Converting reports, research papers, invoices, and legal documents into clean Markdown for search indexing or for feeding into an LLM's context window.
  • •Flagging pages with pages_needing_ocr so a caller can send only specific pages of a Mixed PDF to OCR instead of the whole document.
  • •Running the same detection and conversion logic client-side in a browser via the WASM build, for tools that can't ship every PDF to a backend.

Installation across platforms

Python: pip install maturin, then maturin develop --release to build the PyO3 bindings locally (the Quick Start doesn't mention a prebuilt wheel). Node.js: npm install @firecrawl/pdf-inspector for the napi-rs bindings. Browser: npm install @firecrawl/pdf-inspector-wasm for the WebAssembly build. Rust: cargo add pdf-inspector, or add pdf-inspector = "0.1" to Cargo.toml manually, pulling from crates.io. CLI: cargo install pdf-inspector installs the pdf2md and detect-pdf binaries; from a source checkout, run them via cargo run --bin pdf2md -- document.pdf instead.

Code examples for integration

In Python, pdf_inspector.process_pdf("document.pdf") returns an object with pdf_type (one of "text_based", "scanned", "image_based", "mixed") and a markdown string that's None when there's nothing to extract. In Node.js, processPdf(readFileSync('document.pdf')) from @firecrawl/pdf-inspector returns the equivalent pdfType (PascalCase: "TextBased", "Scanned", "ImageBased", "Mixed") and markdown. The WASM build mirrors the Node API but takes a Uint8Array you fetch yourself: processPdf(pdf) after await init(). In Rust, pdf_inspector::process_pdf("document.pdf")? returns a result.pdf_type enum and an Option<String> in result.markdown. The pdf2md CLI wraps the same logic for shell use — pdf2md document.pdf --json pipes structured output, --select-pages 1,3,5-10 limits it to specific pages, and --compact collapses long dot leaders and similar padding for token-efficient output.

Strengths

  • ✓The benchmark's own numbers put pdf-inspector at 0.875 overall on the 200-PDF opendataloader-bench corpus with a 0.470s median run, versus pymupdf4llm's 0.735/17.117s and markitdown's 0.589/16.165s — a real gap, not a marginal one, given all five parsers were scored the same way with OCR disabled.
  • ✓The classify-then-route numbers in the README — about 20ms to classify a PDF, about 150ms to extract a TextBased one locally, versus 2-10s for an OCR service — make it straightforward to estimate what a pipeline would save by adding this step.
  • ✓Pure Rust with a single dependency on lopdf and no ML model weights: nothing to license, nothing to run on a GPU, and the WASM build ships the identical parser to a browser.
  • ✓MIT license, so there's no copyleft obligation to work around when embedding it in a closed-source pipeline.

Understanding pdf-inspector's scope

  • △No OCR of its own — pdf-inspector detects scanned and image-based pages and lists which ones need OCR, but extracting text from them is left to a separate service.
  • △The Python bindings, per the Quick Start, are built locally with maturin develop --release rather than installed from a prebuilt wheel.
  • △The benchmark README compares pdf-inspector against four other engines on one 200-PDF corpus with OCR disabled; it says nothing about how classification confidence holds up on PDFs from unusual or malformed tooling outside that set.
  • △Markdown conversion depends on font-size ratios and font-name patterns (Bold, Italic, Courier, etc.) to infer structure, so a PDF that doesn't encode those signals cleanly will produce flatter Markdown.

Comparing with other PDF parsers

MarkItDown — Microsoft's Markdown converter, benchmarked in the same README table at 0.589 overall and a 16.165s run versus pdf-inspector's 0.875 and 0.470s, though it covers more file formats beyond PDF. ↗PyMuPDF4LLM — a Python-only wrapper around PyMuPDF; the same benchmark puts it at 0.735 overall and 17.117s for the 200-PDF run, well behind pdf-inspector on table structure (TEDS 0.401) and speed.LiteParse — the closest competitor in the README's numbers (0.873 overall, 0.811 on headings, actually ahead of pdf-inspector there), but slower per run at 0.750s versus 0.470s. ↗OpenDataLoader — scored 0.831 overall in the same comparison, with a notably weaker table score (TEDS 0.489) and a 2.569s run time.

Frequently asked questions

What types of PDFs can pdf-inspector classify?

pdf-inspector sorts PDFs into four categories — TextBased, Scanned, ImageBased, or Mixed — by sampling text and image operators in the content streams, and returns a 0.0-1.0 confidence score with the result.

Does pdf-inspector perform OCR on scanned documents?

pdf-inspector does not run OCR itself. It flags scanned or image-based pages, including a pages_needing_ocr list for Mixed PDFs, so a caller can route just those pages to a separate OCR service.

What programming languages does pdf-inspector support?

pdf-inspector is written in Rust and ships official bindings for Python (via PyO3/maturin), Node.js (via napi-rs), and browser WebAssembly, plus a Rust crate on crates.io and two CLI tools, pdf2md and detect-pdf.

How does pdf-inspector convert PDFs to Markdown?

pdf-inspector rebuilds headings from font-size ratios, detects bullet/numbered/letter lists and monospace code blocks, formats tables from both drawn rectangles and aligned text, and turns bold/italic font patterns and URLs into Markdown syntax.

What is the license for pdf-inspector?

pdf-inspector is released under the MIT license, so it's safe to embed in a closed-source or commercial pipeline without copyleft obligations.

Is pdf-inspector suitable for high-volume PDF processing?

The README's benchmark ran pdf-inspector across a 200-PDF corpus with a 0.470s median run time, and its own use-case example estimates roughly 20ms to classify and about 150ms to extract a text-based PDF locally — figures that support high-volume use, though they come from the project's own benchmark rather than an independent one.

The problem it solves

Most document pipelines treat every incoming PDF the same way: run it through OCR, even when the PDF already has selectable text embedded from a word processor or a LaTeX export. The README puts that waste at roughly 54% of PDFs — the majority — that don't need OCR at all, yet get sent through it anyway because there's no fast, local, dependency-light step to tell text-based and scanned files apart before they reach an OCR service.

Who should try it — and who should skip

Reach for pdf-inspector if you're building an ingestion pipeline in Rust, Python, or Node.js that receives a mix of real PDFs and scans, and you want to skip OCR costs for the ones that already have text — the classification step alone, at roughly 10-50ms per document, pays for itself once volume is high enough. Skip it if every PDF you handle is scanned or image-based from the start: pdf-inspector will correctly tell you that, but it hands the actual OCR work to something else, so you'd be adding a step that never finds anything to extract.

Related repositories

Source & attribution

Facts and figures sourced from the pdf-inspector GitHub repository (github.com/firecrawl/pdf-inspector), including its README and benchmark table.

GitHub data · last synced Aug 14, 2026Reviewed by Henry
← Back to TopGit

Want a second opinion on pdf-inspector?

Ask an AI that can read this page — one click and you get its take on pdf-inspector.

GitHub