pdf-inspector:基于 Rust 的 PDF 分类与文本提取工具项目

Fast Rust library for PDF inspection, classification, and text extraction. Intelligently detects scanned vs text-based PDFs to enable smart routing decisions.

Branch241Tags32

pdf-inspector

Crates.io npm PyPI License: MIT

用于 PDF 分类与文本提取的快速 Rust 库。默认情况下,它会判断 PDF 是基于文本还是扫描件,提取带位置信息的文本,并在不使用 OCR 的情况下转换为干净的 Markdown。原生 Rust 与 CLI 调用方可选择启用选择性 OCR。提供 Python、Node.js 与 浏览器 WebAssembly 绑定。

由 Firecrawl 构建,用于在本地 200 毫秒内处理文本型 PDF,并为约 54% 无需 OCR 的 PDF 跳过高成本 OCR 服务。

功能

  • 智能分类 — 通过采样内容流,在约 10-50 毫秒内识别 TextBased、Scanned、ImageBased 或 Mixed 类型 PDF。返回置信度得分(0.0-1.0)及逐页 OCR 路由。
  • 文本提取 — 位置感知提取,提供字体信息、X/Y 坐标,并自动确定多栏阅读顺序。旋转文本片段(页边印章、图表轴标题)保留真实的轴对齐包围盒,并报告其 rotation 角度,而不是收缩为零宽度。
  • Markdown 转换 — 标题(根据字号比例识别 H1-H4)、无序/有序/字母列表、代码块(等宽字体检测)、表格(基于矩形和启发式方法)、加粗/斜体格式、URL 链接以及分页符。
  • 表格检测 — 双模式:基于 PDF 绘图指令的矩形检测,以及基于文本对齐的启发式检测。可处理财务表格、脚注以及跨页续表。
  • CID 字体支持 — 针对 Type0/Identity-H 字体的 ToUnicode CMap 解码,支持 UTF-16BE、UTF-8 和 Latin-1 编码。
  • 多栏布局 — 自动识别报纸式分栏、顺序阅读顺序,并支持 RTL 文本。
  • 编码问题检测 — 自动标记损坏的字体编码,以便调用方回退到 OCR。
  • 选择性 OCR — Rust、CLI、Python 和 Node 可仅渲染需要 OCR 的页面,在本地运行 PP-OCRv6 Small,并保留逐页溯源信息及托管回退建议。
  • 单次文档加载 — 文档仅解析一次,并在检测与提取之间共享,避免重复 I/O。
  • 浏览器 WebAssembly — 在浏览器和 Web Workers 中本地运行同一套 Rust 解析器,内嵌 CMap 且无需服务器往返。
  • 默认轻量 — 默认的 Rust 和浏览器构建保持纯提取。原生 Python 和 Node 包包含 OCR 集成,但 PDFium、ONNX Runtime 和模型文件仍为外部依赖,仅当页面被路由到 OCR 时才会被加载。

基准测试

已在 opendataloader-bench 语料库(200 个 PDF)上完成评测。仅展示不采用基于模型的 PDF 解析的本地引擎;评测时禁用了 OCR。分数范围为 0 到 1,越高越好。

引擎 综合 阅读顺序(NID) 表格(TEDS) 标题(MHS) 速度(200 份文档)
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

结果已于 2026 年 7 月 31 日在 Apple M4 Pro 上更新。各引擎版本分别为 pdf-inspector 0.2.6、LiteParse 2.10.1、OpenDataLoader 2.2.1、PyMuPDF4LLM 0.2.0 和 MarkItDown 0.1.5。速度指标是在一次不计入统计的预热运行之后,对五个交替或轮换的完整语料库运行结果取中位数;每个解析器都在单个进程中顺序处理文档。

完整的解析器配置、逐文档预测结果、评测器输出以及生成的图表,均可在可复现结果分支中获取。

最佳适用场景: 需要兼顾速度、阅读顺序和表格结构的原生文本 PDF。在本组对比中,pdf-inspector 取得了更高的综合、阅读顺序和表格得分,并且完整运行速度最快。因此,对于需要生成干净、结构化 Markdown,又不希望引入 OCR 延迟或额外基础设施的报告、研究论文、金融文档、发票和法律 PDF,它都是可靠的本地默认选择。

使用配对基准测试工具,在完全相同的语料库与评测器修订版本上比较两个本地构建。

快速开始

Python

pip install pdf-inspector
import pdf_inspector

result = pdf_inspector.process_pdf("document.pdf")
print(result.pdf_type)   # "text_based", "scanned", "image_based", "mixed"
print(result.markdown)   # Markdown string or None

# Selective OCR; clean text PDFs do not load the external OCR runtime.
ocr = pdf_inspector.process_pdf_with_ocr("document.pdf")
print(ocr.pages_routed_to_ocr)

完整 API 参考:docs/python.md

Node.js

npm install @firecrawl/pdf-inspector
import { readFileSync } from 'fs';
import { processPdf, processPdfWithOcr } from '@firecrawl/pdf-inspector';

const pdf = readFileSync('document.pdf');
const result = processPdf(pdf);
console.log(result.pdfType);   // "TextBased", "Scanned", "ImageBased", "Mixed"
console.log(result.markdown);  // Markdown string or null

const ocr = await processPdfWithOcr(pdf); // selective OCR, off the event loop
console.log(ocr.pagesRoutedToOcr);

完整 API 参考:napi/README.md

浏览器 WebAssembly

npm install @firecrawl/pdf-inspector-wasm
import init, { processPdf } from '@firecrawl/pdf-inspector-wasm';

await init();
const response = await fetch('/document.pdf');
const pdf = new Uint8Array(await response.arrayBuffer());
const result = processPdf(pdf);

console.log(result.pdfType);
console.log(result.markdown);

完整 API 参考:wasm/README.md

Rust

从 crates.io 安装:

cargo add pdf-inspector

或手动添加:

[dependencies]
pdf-inspector = "1"
use pdf_inspector::process_pdf;

let result = process_pdf("document.pdf")?;
println!("Type: {:?}", result.pdf_type);
if let Some(markdown) = &result.markdown {
    println!("{}", markdown);
}

完整 API 参考:docs/rust-api.md

CLI

# Install the CLI tools
cargo install pdf-inspector

# Convert PDF to Markdown
pdf2md document.pdf

# JSON output (for piping), with the document information (title, author, producer, dates, ...)
pdf2md document.pdf --json

# Positioned TextItem JSON (coordinates relative to the visible page box): axis-aligned box, rotation, font, paint (fill and stroke colour, render mode), underline metadata
pdf2md document.pdf --items-json

# Raw markdown only (no headers)
pdf2md document.pdf --raw

# Token-efficient output (collapses long dot leaders and similar source padding)
pdf2md document.pdf --compact

# Insert page break markers (<!-- Page N -->)
pdf2md document.pdf --pages

# Process only specific pages
pdf2md document.pdf --select-pages 1,3,5-10

# Detection only (no extraction)
detect-pdf document.pdf
detect-pdf document.pdf --json

# Detection + layout analysis (tables, columns)
detect-pdf document.pdf --analyze --json

Rust 与 CLI 使用者可在构建时选择启用 OCR:

cargo install pdf-inspector --features ocr --bin pdf2md
PDFIUM_LIB_PATH=/path/to/libpdfium ORT_DYLIB_PATH=/path/to/libonnxruntime \
  pdf2md scan.pdf --ocr auto --json

OCR JSON 封装结构采用版本化设计,并报告已路由页面、各页来源与置信度、警告,以及建议进入托管文档流水线的页面。原生 Python 和 Node 包可提供相同流水线,且无需源码构建功能。所有原生入口点仅在启用 OCR 路由时,才需要单独安装的 PDFium 和 ONNX Runtime 库。固定版本下载、平台支持、模型缓存行为以及托管回退集成,请参阅 OCR 运行时配置指南。更底层的控制选项,请参阅 Rust API 指南。

在源码检出环境中,请改用 cargo run --bin pdf2md -- document.pdf 或 cargo run --bin detect-pdf -- document.pdf。

架构

PDF bytes
  │
  ├─► detector         → PdfType (TextBased / Scanned / ImageBased / Mixed)
  │
  └─► extractor
        ├─ fonts        → font widths, encodings
        ├─ content_stream → walk PDF operators → TextItems + PdfRects
        ├─ xobjects     → Form XObject text, image placeholders
        ├─ links        → hyperlinks, AcroForm fields
        └─ layout       → column detection → line grouping → reading order
              │
              ├─► tables
              │     ├─ detect_rects      → rectangle-based tables (union-find)
              │     ├─ detect_heuristic  → alignment-based tables
              │     ├─ grid              → column/row assignment → cells
              │     └─ format            → cells → Markdown table
              │
              └─► markdown
                    ├─ analysis     → font stats, heading tiers
                    ├─ preprocess   → merge headings, drop caps
                    ├─ convert      → line loop + table/image insertion
                    ├─ classify     → captions, lists, code
                    └─ postprocess  → cleanup → final Markdown

文档仅通过 load_document_from_path / load_document_from_mem 加载 一次,并在检测与提取阶段之间共享,因此不会产生重复解析。

项目结构

src/
  lib.rs                — Public API, PdfOptions builder, convenience functions
  python.rs             — PyO3 Python bindings
  types.rs              — Shared types: TextItem, TextLine, PdfRect, ItemType
  text_utils.rs         — Character/text helpers (CJK, RTL, ligatures, bold/italic)
  process_mode.rs       — ProcessMode enum (DetectOnly, Analyze, Full)
  detector.rs           — Fast PDF type detection without full document load
  glyph_names.rs        — Adobe Glyph List → Unicode mapping
  tounicode.rs          — ToUnicode CMap parsing for CID-encoded text
  extractor/            — Text extraction pipeline
  tables/               — Table detection and formatting
  markdown/             — Markdown conversion and structure detection
  bin/                  — CLI tools (pdf2md, detect_pdf)
napi/                   — Node.js/Bun bindings (napi-rs)
wasm/                   — Browser bindings (wasm-bindgen)

分类原理

  1. 解析 xref 表与页面树(不加载完整对象)
  2. 根据 ScanStrategy 选择页面(默认:抽取 8 页样本)
  3. 在内容流中查找 Tj/TJ(文本操作符)和 Do(图像操作符)
  4. 根据采样页面中是否存在文本操作符进行分类

可在毫秒内识别 300 多页的 PDF。结果包含 pages_needing_ocr——一个列出缺少文本的具体页码的列表,从而支持按页路由 OCR,而不是全有或全无。

扫描策略

策略 行为 适用场景
EarlyExit 扫描所有页面,遇到第一个非文本页面即停止 适用于将文本型 PDF 路由到快速提取流程的管道
Full 扫描所有页面,不提前退出 准确区分混合型与扫描型 PDF
Sample(n)(默认:Sample(8)) 均匀抽取 n 页(首页、末页、中间页) 更重视速度而非精度的超大 PDF
Pages(vec) 仅扫描指定的从 1 开始的页码 调用方已知需要检查哪些页面时

Markdown 输出

转换器可处理:

元素 检测方式
标题(H1-H4) 相对于正文文字的字号层级,并按 0.5pt 聚类
粗体/斜体 字体名称模式(Bold、Italic、Oblique)
无序列表 •、-、*、○、●、◦ 前缀
有序列表 1.、1)、(1) 模式
字母列表 a.、a)、(a) 模式
代码块 等宽字体(Courier、Consolas、Monaco、Menlo、Fira Code、JetBrains Mono)及关键字检测
表格 基于 PDF 绘图操作的矩形检测 + 基于文本对齐的启发式检测
财务表格 针对合并数值的分词拆分
题注 检测 “Figure”、“Table”、“Source:” 前缀
下标/上标 相对于基线的字号与 Y 偏移
URL 转换为 Markdown 链接
断词连字符 重新合并跨行断开的单词
页码 从输出中过滤
首字放大 大号首字母与后续文本合并
点引导线 目录风格的点线压缩为 " ... "

适用场景:智能 PDF 路由

pdf-inspector 专为大规模 PDF 处理流程而设计。无需将每一份 PDF 都送入 OCR:

PDF arrives
  → pdf-inspector classifies it (~20ms)
  → TextBased + high confidence?
      YES → extract locally (~150ms), done
      NO  → send to OCR service (2-10s)

这对大多数已经是文本型 PDF 的文件(如报告、论文、发票、法律文件)可节省成本并降低延迟。

调试

关于 RUST_LOG 环境变量的用法,参见 docs/debugging.md。

许可

MIT

Introduction

用于 PDF 检查、分类和文本提取的快速 Rust 库。智能检测扫描型与文本型 PDF,助力实现智能路由决策。【此简介由AI生成】

Customize your domain
5819.66 K1.33 KVisit GitHub