TOOLPIPO LAB PDF · 21種類
文字が見えるのに検索・コピーできないPDFは、何が違う?
PDF画面には文字が見えるのに、検索やコピーができない。画像だけのPDF、見えない文字を重ねたPDF、同じ位置に二重の文字を置いたPDFを自作し、見た目と抽出テキストの違いを確認しました。
公開日・検証日:2026年10月11日
文字が見えることと、文字データがあることは別でした
通常のHELLOは5文字を抽出。画像だけのHELLOは0文字でした。画像にmode3の不可視文字を重ねたPDFでは、5文字・画像描画1・不可視描画1を検出しました。通常の画像+可視文字はOCR候補になりませんでした。
同位置の二重文字は重複候補1グループ、離れた同じ単語は0。ページ外候補1項目、Unicode候補4文字を検出しました。抽出テキストが存在しても、正しい検索・コピーができるとは限りません。候補は原本と照らして確認するための手がかりです。
今回の検証条件
- 入力
- 既存の自作PDF21種類。主要11条件を本文で比較。実在資料・個人情報なし。
- 測定方法
- 現行Tool本体とPDF.js 6.3.289で再測定。ページごとのJSONを公開します。
- Tool
- PDF検索・コピー/OCRテキストレイヤーチェッカー。OCRを追加・修復するToolではありません。
同じHELLOでも、画像だけなら抽出文字は0
通常テキストと画像だけのPDFは、どちらもHELLOの見た目を持ちます。通常テキストは文字データと描画命令を持ち、画像だけのPDFは文字の形を画素として保存しています。このToolは画像から文字を読み取るOCRを行いません。
画像+不可視文字をOCR候補として区別できました
画像に可視文字を重ねた条件も、不可視文字を重ねた条件も抽出文字は5でした。不可視の条件だけがOCRテキストレイヤー候補になりました。今回はOCRソフトを使わず、意図して文字を配置したOCR風の自作PDFです。OCR処理済みか、画像の文字と正しく一致するかは判定していません。
条件は同じページで「空白以外の抽出文字>0」「raster画像描画>0」「mode3のテキスト描画>0」が揃うこと。透明度、白文字、細工された重ね合わせを全て検出する条件ではありません。mode4–7のclipping描画はmode3と別集計です。
主要11条件の測定結果
以下の数値は文書内のページ合計です。raster画像描画はPDF.jsの画像描画命令数であり、ユニークな実画像の個数ではありません。文字数は空白を除いた抽出文字数です。
| 条件 | 抽出文字(空白除外) | raster画像描画 | 不可視文字描画 | Tool判定 |
|---|---|---|---|---|
| 通常テキスト | 5 | 0 | 0 | テキスト中心 |
| 画像のみ | 0 | 1 | 0 | 画像中心・抽出テキストなし |
| 画像+可視テキスト | 5 | 1 | 0 | 画像と抽出テキストが混在 |
| 画像+不可視テキスト(OCR風) | 5 | 1 | 1 | 画像と抽出テキストが混在(OCR候補 1ページ) |
| 同位置の二重文字 | 10 | 0 | 0 | テキスト中心 |
| 別位置の同じ単語 | 10 | 0 | 0 | テキスト中心 |
| ページ外候補 | 11 | 0 | 0 | テキスト中心 |
| Unicode候補 | 4 | 0 | 0 | テキスト中心 |
| 0 / 90 / 180 / 270°回転 | 20 | 0 | 0 | テキスト中心 |
| vector図形のみ | 0 | 0 | 0 | 抽出テキストなし |
| 6ページ混在 | 25 | 3 | 2 | テキスト中心/画像と抽出テキストが混在/画像中心・抽出テキストなし(OCR候補 2ページ) |
| 条件 | 重複グループ | ページ外項目 | Unicode文字 |
|---|---|---|---|
| 通常テキスト | 0 | 0 | 0 |
| 画像のみ | 0 | 0 | 0 |
| 画像+可視テキスト | 0 | 0 | 0 |
| 画像+不可視テキスト(OCR風) | 0 | 0 | 0 |
| 同位置の二重文字 | 1 | 0 | 0 |
| 別位置の同じ単語 | 0 | 0 | 0 |
| ページ外候補 | 0 | 1 | 0 |
| Unicode候補 | 0 | 0 | 4 |
| 0 / 90 / 180 / 270°回転 | 0 | 0 | 0 |
| vector図形のみ | 0 | 0 | 0 |
| 6ページ混在 | 0 | 0 | 0 |
同じ文字でも、同位置の重なりだけが重複候補
同位置にHELLOを2回描いた条件は、抽出文字10・重複候補1グループ。別位置のHELLOを2回描いた条件は、抽出文字10・重複候補0でした。三重文字も1つの連結グループになります。影や縁取り、意図した重ね文字でも候補になるため、「二重OCR」と断定できません。
現行条件はNFKC正規化・連続空白の圧縮・前後空白除去後に2文字以上で、文字列が一致し、概算枠のIoU(重なり面積÷合併面積)が0.80以上になる組を連結します。
ページ外候補とUnicode候補は、抽出された項目だけ
ページ外fixtureは11文字を抽出し、1項目を候補にしました。ページ境界を外側へ2pt広げた領域に対し、概算枠の内側面積÷枠面積が0.5未満のとき候補です。境界上の50%ちょうどは含みません。1ptの軽いはみ出しは0でした。
PDF.jsがページ外の文字を先に除外する場合があり、原本のページ外文字の完全列挙ではありません。枠はglyphの輪郭ではなく概算です。縦書き・斜体・複雑なフォントで見た目とずれる場合があります。
Unicode fixtureから実際に検出したのはU+FFFD、U+E000、U+F0000、U+0001の4文字です。原本の対応表にはU+200B・U+202E・U+FEFFもありますが、今回PDF.jsの抽出結果には残りませんでした。抽出されなかった文字をToolが検出したとは扱いません。候補の存在だけで破損と判断できません。
回転と混在ページは、ページ単位で確認
0・90・180・270°の通常テキストは、いずれもページ外候補0でした。文字枠の向きもプレビューで確認します。vector図形だけのPDFは抽出文字0・raster画像描画0で「抽出テキストなし」でした。文字が抽出できないPDFを全て画像だけと分類しません。
6ページ混在文書は抽出テキストあり1–4, 6ページ、抽出テキストなし5ページ、OCR候補3–4ページでした。文書全体を一括で「検索できる/できない」と判定すると、ページごとの差を見落とします。
自分のPDFでは、候補ページを原本と見比べる
- PDFを選び、抽出文字のないページやOCR候補を確認します。
- 重複・ページ外・Unicode候補のページを開き、文字枠と原本を照らします。
- 実際に使うビューアで、必要な文字の検索とコピーを確認します。
Toolはブラウザ内で処理し、PDF本文・ファイル・解析情報を外部へ送信しません。コピー/CSVにPDF本文は含めません。最大50MB・500ページ。パスワード付きPDFは対象外です。
この検証で保証しないこと
検索・コピーの正しさ、OCR精度、読み順、全ての透明文字の検出、別ビューアの動作、PDF/UA適合やアクセシビリティ、修復・マルウェア判定・安全性は保証しません。画像の内容と抽出文字の意味を比較する機能もありません。今回の21種類で全てのPDFを代表するものではありません。
再現PDFと実測データ
既存fixtureを変更せず使用しました。21 PDFにREADME・results.json・フォントのライセンスを添えたZIPです。独立したフォントbinaryは配布しません。保護PDF・破損PDFの2種類は意図した拒否テストです。
再現ZIPをダウンロード · ページ別の実測JSON · README
ZIP:32,529 bytes / SHA-256:2775e721d5cefd53ebbbf078894bbd7515d4175a125f68ec57c2ba72bc86ca20
各PDFのbytes・SHA-256、ページ別の文字項目数、画像・不可視・clipping描画、重複・ページ外・Unicode候補、分類をJSONに記録しています。ZIP内JSONは循環hashを避けるためZIP自身のhashを省き、公開JSONに最終ZIPの情報を付けています。
開発時に確認した21種類のPDFを見る
全ページ合計。拒否したPDFの分類欄はエラー表示で、数値0は解析成功を意味しません。
| fixture | ページ | 分類 | text items | 画像描画 | 不可視描画 | 重複 | ページ外 | Unicode | 備考 |
|---|---|---|---|---|---|---|---|---|---|
| a-native.pdf | 1 | テキスト中心 | 1 | 0 | 0 | 0 | 0 | 0 | 通常テキスト |
| b-image-only.pdf | 1 | 画像中心・抽出テキストなし | 0 | 1 | 0 | 0 | 0 | 0 | 画像のみ |
| c-visible-image.pdf | 1 | 画像と抽出テキストが混在 | 1 | 1 | 0 | 0 | 0 | 0 | 画像+可視テキスト |
| d-ocr-like.pdf | 1 | 画像と抽出テキストが混在(OCR候補 1ページ) | 1 | 1 | 1 | 0 | 0 | 0 | 画像+不可視テキスト(OCR風) |
| f-duplicate.pdf | 1 | テキスト中心 | 2 | 0 | 0 | 1 | 0 | 0 | 同位置の二重文字 |
| g-separate.pdf | 1 | テキスト中心 | 2 | 0 | 0 | 0 | 0 | 0 | 別位置の同じ単語 |
| h-outside.pdf | 1 | テキスト中心 | 1 | 0 | 0 | 0 | 1 | 0 | ページ外候補 |
| i-small-bleed.pdf | 1 | テキスト中心 | 1 | 0 | 0 | 0 | 0 | 0 | 1ptのはみ出し。2pt余白内のため候補0 |
| j-unicode.pdf | 1 | テキスト中心 | 3 | 0 | 0 | 0 | 0 | 4 | Unicode候補 |
| l-vector.pdf | 1 | 抽出テキストなし | 0 | 0 | 0 | 0 | 0 | 0 | vector図形のみ |
| m-triple.pdf | 1 | テキスト中心 | 3 | 0 | 0 | 1 | 0 | 0 | 同位置の三重文字。連結した1グループ |
| q-form.pdf | 1 | テキスト中心 | 2 | 0 | 1 | 1 | 0 | 0 | Form内の不可視文字。画像なしのためOCR候補ではない |
| r-save-restore.pdf | 1 | テキスト中心 | 3 | 0 | 2 | 0 | 0 | 0 | save/restoreをまたぐ描画モード |
| s-clip.pdf | 1 | テキスト中心 | 1 | 0 | 0 | 0 | 0 | 0 | mode7のclipping描画1。不可視mode3と別集計 |
| e-mixed.pdf | 6 | テキスト中心/画像と抽出テキストが混在/画像中心・抽出テキストなし(OCR候補 2ページ) | 5 | 3 | 2 | 0 | 0 | 0 | 6ページ混在 |
| k-rotations.pdf | 4 | テキスト中心 | 4 | 0 | 0 | 0 | 0 | 0 | 0 / 90 / 180 / 270°回転 |
| n-20-pages.pdf | 20 | テキスト中心 | 20 | 0 | 0 | 0 | 0 | 0 | 通常テキスト20ページ |
| n-100-pages.pdf | 100 | テキスト中心 | 100 | 0 | 0 | 0 | 0 | 0 | 通常テキスト100ページ |
| o-password.pdf | 1 | パスワード付きPDFには対応していません。 | 0 | 0 | 0 | 0 | 0 | 0 | 意図したパスワード拒否 |
| p-malformed.pdf | 取得不能 | PDFを解析できませんでした。破損または対応外のPDFの可能性があります。 | 0 | 0 | 0 | 0 | 0 | 0 | 意図した破損PDF拒否 |
| sample.pdf | 4 | テキスト中心/画像中心・抽出テキストなし/画像と抽出テキストが混在(OCR候補 1ページ) | 4 | 2 | 1 | 1 | 0 | 0 | 通常・画像・OCR風・二重文字の公開サンプル |
測定時の実装と再現方法
測定元commit:82029598bcffba31b591d57e9ccf0ff489c493f3。現行ToolのanalyzeBytesを直接使用しています。
- node scripts/measure-pdf-text-layer-article.mjs
- python scripts/package-pdf-text-layer-article.py
- node scripts/render-pdf-text-layer-article.js