OCR がスキャン PDF をどう読むか。そしてこのツールが Markdown を返す理由
スキャン PDF は文字を写した画像にすぎない。この OCR エンドポイントが返すのは Markdown で、隠しテキスト層付き PDF ではない。Auto は既存テキストを使い、Force は全ページを読み直す。

スキャン PDF はページをラスタ画像として保持している。選択できる文字ではなく、文字を撮影した写真だ。OCR(光学文字認識)はその画素を調べ、どの形が文字かを推測して実際のテキストを出力する。PDF123 では無料のブラウザツールとしても POST /api/v1/misc/ocr-pdf としても動作し、応答は Markdown であって、書き換えられた PDF ではない。
スキャンは依然として画像である
OCR はビットマップをきれいにしたり、先鋭化したり、置き換えたりしない。OCR が読み違えた鮮明なスキャンは、見た目こそ鮮明なままだ。品質のボトルネックは画像ではなく認識の方にあった。同じ一群のスキャンで認識エンジンを差し替えるだけで精度は大きく変わり得るが、画素そのものは何も変わっていない。
従来の PDF OCR は、画像の下に位置合わせした不可視のテキスト層を書き込み、選択や検索が正しい語に当たるようにする。図が示しているのはそれで、多くのデスクトップツールは今もそう動く。
このエンドポイントが実際に返すもの
OCR の経路は /api/v1/misc/ocr-pdf を呼ぶ。これはスタンドアロンの Rust クレート pdf-inspector(ocr フィーチャーを有効にしてビルドしたもの)の上で動いている。PDF 全体を認識モデルに渡すわけではない。pdf-inspector はまず各ページを、すでに抽出可能なネイティブテキストを持つページか、画像のみのページかに分類する。ネイティブテキストを持つページはそのテキストをそのまま使い、認識モデルには一切触れない。画像のみのページは認識パイプラインに回され、PDFium(Chrome が内部で使っているのと同じオープンソースのレンダラー)がページをラスタライズし、ONNX Runtime が PP-OCRv6 Small モデルを実行して読み取る。どちらのページの結果も順番どおりに 1 つの Markdown 文書へつなぎ合わされる。応答が text/markdown になり、ダウンロードが .md で終わるのはこのためだ。
この仕様は今回の書き換えで初めて生まれたものだ。このプロジェクトが以前運用していた Java/Spring Boot バックエンドは OCRmyPDF を呼んでいた。これは「画像に隠しテキスト層を重ねる」という従来型のアプローチで、出力も PDF だった。Rust への書き換えはこの経路を pdf-inspector の選択的 OCR にまるごと置き換え、それに伴って出力も PDF から Markdown へ変わった。旧 Java バックエンドはリポジトリからすでに削除されており、切り戻せるトグルではない。
検索可能な PDF(画像+テキスト層)が必要なら、このエンドポイントはそれを返せない。返せるのは、エージェントやデータパイプラインがそのまま読み込めるテキストだ。
Auto と Force OCR
フォームには ocrType フィールドがある。
- Normal(
force-ocr以外はすべて)は Auto に対応する。ファイルに既存のテキストがあればそれを使い、画像のみのページで OCR を走らせる。きれいなボーンデジタル PDF では、Auto は OCR ランタイムを読み込まない。 - Force OCR(
ocrType=force-ocr)は、すでにテキスト層があるページを含めて全ページで認識をやり直す。画像のみのページでは精度ではなく時間を余分に払うことになる。壊れた、あるいは部分的な既存層を無視した結果を得たい場合に効く。
ポータルの既定は Force OCR だ。言語の指定はできない。旧 Java 経路から残っていた言語パラメータはサーバー側で無視される。
Auto と Force の切り分けはリクエストの内部だけで起きており、ポータルも API のケイパビリティプローブも事前にはそれを確認してくれない。GET /api/v1/settings/get-endpoints-status は ocr-pdf を常に「enabled」と報告するだけで、PDFium、ONNX Runtime、PP-OCRv6 モデルが実際にインストールされているかまでは検証しない。本当のチェックが働くのは、リクエストが認識処理を発火させた瞬間だ。いずれかが欠けていればエンドポイントは 503 を返す。ネイティブテキストのみにこっそりフォールバックした劣化版 Markdown にはならない。PP-OCRv6 Small モデル自体は約 31 MB あり、デプロイ時にローカルキャッシュへ事前配置していない限り、実際に認識が必要な最初のページでネットワーク越しにダウンロードされる。事前配置済みモデルを持たないオフライン環境では、最初の Force リクエストで速度が落ちるどころか、その場で失敗する可能性が高い。
認識は確率的である
エンジンは画素のパターンを文字や語のモデルに照合する。きれいでコントラストが高く、標準的なフォントで印刷された文書ではよく当たるが、次のような場合は精度が落ちる。
- 低解像度または低コントラストのスキャン(ファックス品質と 300 DPI の原本の違い)
- 手書き、装飾フォント、特殊なレイアウト(多段の表、回転したテキスト、密度の高い帳票)
- 字形をわずかに歪める程度に傾いたページ。照合がちょうど混乱する
ぼやけたファックスは、Auto でも Force でも、きれいなスキャンのようには OCR できない。これはモデル自体の限界であり、パラメータで直せるものではない。
OCR がしないこと
OCR が与えるのはテキストだ。段落、見出し、表、リフロー可能な Word 文書を組み立て直すことはしない。編集可能なレイアウトは認識誤差の上に載る変換の問題であり、スキャンを読むこととは別の仕事だ。
PDF の OCR はサーバー側で動作し、アカウントは不要だ。ダウンロードされるのは Markdown である。既存のテキスト層が誤っているように見えるなら、Force OCR を使って Auto にその層を信用させないようにする。あるマシンに PDFium とモデルが本当にインストールされているかを知りたいなら、ケイパビリティプローブの状態を読むより実際にリクエストを 1 回実行するほうが確実だ。プローブが確認しているのはエンドポイントの存在だけで、実行環境の準備ができているかどうかではない。自動化用のキーと OpenAPI は 開発者向け にある。