OpenSource-Hub

pdf-inspector

ライブラリ

firecrawl/pdf-inspector

PDF の分類、テキスト抽出、Markdown 変換のための高速な Rust ライブラリ。

概要

高性能な Rust ライブラリで、PDF がテキスト型かスキャン版かを検出し、位置情報付きのテキストを抽出して、OCR なしでクリーンな Markdown に変換します。Python、Node.js、WebAssembly バインディングおよび CLI ツールを提供し、インテリジェントなルーティングにより、ほとんどのテキスト型 PDF の OCR 処理をスキップします。

README プレビュー

# pdf-inspector\n\n[](https://crates.io/crates/pdf-inspector)\n[](https://www.npmjs.com/package/@firecrawl/pdf-inspector)\n[](https://pypi.org/project/pdf-inspector/)\n[](LICENSE)\n\nFast Rust library for PDF classification and text extraction. Detects whether a PDF is text-based or scanned, extracts text with position awareness, and converts to clean Markdown — all without OCR. Includes bindings for [Python](docs/python.md), [Node.js](napi/README.md), and [browser WebAssembly](wasm/README.md).\n\nBuilt by [Firecrawl](https://firecrawl.dev) to handle text-based PDFs locally in under 200ms, skipping expensive OCR services for the ~54% of PDFs that don't need them.\n\n## Features\n\n- **Smart classification** — Detect TextBased, Scanned, ImageBased, or Mixed PDFs in ~10-50ms by sampling content streams. Returns a confidence score (0.0-1.0) and per-page OCR routing.\n- **Text extraction** — Position-aware extraction with font info, X/Y coordinates, and automatic multi-column reading order.\n- **Markdown conversion** — Headings (H1-H4 via font size ratios), bullet/numbered/letter lists, code blocks (monospace font detection), tables (rectangle-based and heuristic), bold/italic formatting, URL linking, and page breaks.\n- **Table detection** — Dual-mode: rectangle-based detection from PDF drawing ops, plus heuristic detection from text alignment. Handles financial tables, footnotes, and continuation tables across pages.\n- **CID font support** — ToUnicode CMap decoding for Type0/Identity-H fonts, UTF-16BE, UTF-8, and Latin-1 encodings.\n- **Multi-column layout** — Automatic detection of newspaper-style columns, sequential reading order, and RTL text support.\n- **Encoding issue detection** — Automatically flags broken font encodings so callers can fall back to OCR.\n- **Single document load** — The document is parsed once and shared between detection and extraction, avoiding redundant I/O.\n- **Browser WebAssembly** — Run the same Rust parser locally in browsers and Web 

FAQ (5)

トラブル対応
AWS LambdaまたはAmazon Linux 2023で@firecrawl/pdf-inspectorを読み込む際に発生する「GLIBC_2.35 not found」エラーを修正するにはどうすればよいですか?

バージョン 1.13.0〜1.17.0 の x64 GNU バイナリは --use-napi-cross なしでビルドされたため、GLIBC_2.35 を必要とし、Amazon Linux 2023、RHEL 9、Rocky Linux 9 などの glibc 2.34 ホストで失敗します。紛らわしい Cannot find module エラーが、loadErrors に含まれる実際の GLIBC_2.35 not found エラーを隠すことがあります。

恒久的なリリース修正: .github/workflows/publish.yml で x86_64-unknown-linux-gnu ターゲットを napi-cross を使ってビルドします:

- runner: blacksmith-8vcpu-ubuntu-2404
  target: x86_64-unknown-linux-gnu
  build-flags: --use-napi-cross

その後、再ビルドします:

bunx napi build --platform --release \
  --target x86_64-unknown-linux-gnu --use-napi-cross

生成されたバイナリを確認します:

objdump -T pdf-inspector.linux-x64-gnu.node \
  | grep -o 'GLIBC_[0-9.]*' | sort -Vu | tail -1
# expected: GLIBC_2.17

glibc 2.34 ホストでの一時的な回避策: x64 プラットフォームパッケージを、GLIBC_2.34 を要件とする最後のリリースであるバージョン 1.12.0 に固定するか、上記のコマンドでローカルに再ビルドしたバイナリを使用します。パッケージが推移的に取り込まれている場合は、npm の overrides を使用できます:

{
  "overrides": {
    "@firecrawl/pdf-inspector-linux-x64-gnu": "1.12.0"
  }
}

バージョン 1.12.0 は依然として GLIBC_2.34 を必要とするため、Debian 11 などの古いシステムでは役に立ちません。それらのシステムには、再ビルドされた GLIBC_2.17 バイナリまたは修正済みリリースが必要です。この問題を回避するためだけに musl ビルドに切り替えないでください。

参照 Issue #505
トラブル対応
pdf-inspectorで日本語CFF PDFの抽出結果に「針針針」のような無関係な漢字が繰り返し表示される問題を修正するにはどうすればよいですか?

これは、try_remap_subset_cmap が CIDFontType0(CFF)フォントに TrueType のサブセット GID 修復を適用することが原因で発生します。CFF フォントでは、CID は CFF charset を介して解決され、振り直されたグリフ ID ではないため、元の /ToUnicode CMap を再マッピングしてはいけません。

修正するには、PR fix(tounicode): skip subset GID remap for CIDFontType0 (CFF) descendants を含むリリースにアップグレードするか、パッチ適用済みのソースから pdf2md/pdf-inspector をビルドしてください。

src/tounicode.rs に自分でパッチを適用する場合は、W 配列/シーケンシャル再マッピングのチェックの前に、try_remap_subset_cmap 内にガードを追加してください:

// Keep the existing ToUnicode CMap unchanged for CFF fonts.
if descendant_subtype == "CIDFontType0" {
    return None;
}

既存の remap_to_sequential パスは CIDFontType2(TrueType)の子孫フォントに対してのみ有効なままにしてください。その後、再ビルドします:

cargo build --release
cargo run --bin pdf2md -- input.pdf > out.md

影響を受けるバージョンには @firecrawl/pdf-inspector 1.11.2 および @firecrawl/pdf-inspector-wasm 0.1.3 が含まれます。一時的な回避策として、pdfjs-dist 6.0.227 を使用し、getTextContent() で PDF を抽出してください。この破損では有効だが誤った漢字が生成される可能性があるため、U+FFFD 置換文字を数えても検出できないことに注意してください。

参照 Issue #208
トラブル対応
bare LF(19バイトストライド)を使用するクラシックxrefエントリが原因のPDF解析エラー「invalid file trailer」を修正するにはどうすればよいですか?

pdf-inspector を PR #508 を含むリリースまたはビルドにアップグレードしてください。この修正は、エントリが単一の LF バイトで終了している(必須である20バイトの SP LF 終端ではなく19バイトの)従来型の相互参照テーブルを検出し、ファイルの残りの部分を保持したまま、仕様に準拠した SP LF エントリでテーブルをその場で再構築します。これは startxref ポインタの復旧とは別の修正です。一時的な回避策として、pypdf のような寛容なリーダーを使って PDF を書き直し、xref テーブルを再生成してください:

from pypdf import PdfReader, PdfWriter

reader = PdfReader("input.pdf")
writer = PdfWriter(clone_from=reader)

with open("fixed.pdf", "wb") as f:
    writer.write(f)

参照 Issue #473
トラブル対応
pdf-inspectorがPDFからスペイン語のアクセント付き文字(Cámara → CÆmara、código → cdigoなど)を欠落させたり誤変換したりする問題を修正する方法

これは、standard-14 Type1 フォントが /Differences 配列を持たない << /BaseEncoding /WinAnsiEncoding >> のようなエンコーディング辞書を使用している場合に、pdf-inspector 1.20.0 で発生します。pdf-inspector は /BaseEncoding を無視してテキストを StandardEncoding としてデコードするため、0xC0–0xFF の範囲のバイトが誤ったグリフになるか、欠落します。has_encoding_issues が false のままになるのもバグです。

恒久的な修正: フォントエンコーディングの修正「decode simple fonts through their base and built-in encodings and glyph names」を含むリリースに pdf-inspector をアップグレードし、その後ファイルを再抽出してください。

一時的な回避策:

1. このエンコーディングを正しく処理する pypdf 6.10 以降で抽出する:

pip install -U "pypdf>=6.10"

from pypdf import PdfReader

reader = PdfReader("repro.pdf")
text = "\n".join(page.extract_text() for page in reader.pages)
print(text)

2. あるいは、すでに /BaseEncoding を含むエンコーディング辞書に空の /Differences [] 配列を追加して PDF を正規化する:

import pikepdf

with pikepdf.open("repro.pdf") as pdf:
    for page in pdf.pages:
        resources = page.get("/Resources")
        if not isinstance(resources, pikepdf.Dictionary):
            continue
        fonts = resources.get("/Font")
        if not isinstance(fonts, pikepdf.Dictionary):
            continue
        for font in fonts.values():
            encoding = font.get("/Encoding")
            if (
                isinstance(encoding, pikepdf.Dictionary)
                and "/Differences" not in encoding
            ):
                encoding.Differences = pikepdf.Array()
    pdf.save("repro-fixed.pdf")

その後、repro-fixed.pdf に対して pdf-inspector を実行してください。空の /Differences 配列は有効であり、影響を受けるバージョンに /BaseEncoding /WinAnsiEncoding を参照させることができます。

参照 Issue #544
トラブル対応
なぜ extract_pages_markdown() は、小さなネイティブテキストのヘッダーを含むスキャン済みPDFページに対して needs_ocr=False を報告するのですか?

これは、ページの大部分がページ全体のラスタ画像でありながら、ヘッダー、スタンプ、マストヘッドなどの少量の有効なネイティブテキストが含まれている場合に発生します。古いバージョンの extract_pages_markdown() では、needs_ocr が画像カバレッジではなくテキスト品質シグナルのみから計算されていたため、デコード可能なヘッダーによってページがOCR不要と誤って判定されていました。classify_pdf() はこのページを image_based として正しく検出します。

修正: issue #227 の修正を含むリリースに pdf-inspector をアップグレードしてください。この修正では、OCRルーティングに共有の分類ロジックが使用され、マストヘッド付きスキャンページがOCRに送られます。

pip install --upgrade pdf-inspector

影響を受けるバージョンでの回避策: ページごとの needs_ocr フィールドではなく、classify_pdf_bytes().pages_needing_ocr を信頼できる情報源として扱ってください。

import pdf_inspector

cls = pdf_inspector.classify_pdf_bytes(data)
ext = pdf_inspector.extract_pages_markdown_bytes(data)

pages_needing_ocr = set(cls.pages_needing_ocr)

for page_number, page in enumerate(ext.pages):
    if page_number in pages_needing_ocr:
        # page.markdown が空でない場合や page.needs_ocr が False の場合でも OCR を実行します。
        ocr_text = run_ocr_for_page(data, page_number)

抽出されたMarkdownが空でないことをもって、ページがOCRを必要としない証拠としてはいけません。スキャンされた表や本文が欠落しており、ネイティブヘッダーのみが含まれている可能性があります。

参照 Issue #227