TOOLPIPO LAB PDF · 21種類

文字が見えるのに検索・コピーできないPDFは、何が違う?

PDF画面には文字が見えるのに、検索やコピーができない。画像だけのPDF、見えない文字を重ねたPDF、同じ位置に二重の文字を置いたPDFを自作し、見た目と抽出テキストの違いを確認しました。

文字が見えることと、文字データがあることは別でした

通常の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ではありません。
再現データ
21 PDF・README・実測JSON・ライセンスをダウンロード

同じHELLOでも、画像だけなら抽出文字は0

通常テキストと画像だけのPDFは、どちらもHELLOの見た目を持ちます。通常テキストは文字データと描画命令を持ち、画像だけのPDFは文字の形を画素として保存しています。このToolは画像から文字を読み取るOCRを行いません。

通常テキストは5文字、文字画像だけは0文字
通常テキストは5文字、文字画像だけは0文字(説明用概念図)

画像+不可視文字をOCR候補として区別できました

画像に可視文字を重ねた条件も、不可視文字を重ねた条件も抽出文字は5でした。不可視の条件だけがOCRテキストレイヤー候補になりました。今回はOCRソフトを使わず、意図して文字を配置したOCR風の自作PDFです。OCR処理済みか、画像の文字と正しく一致するかは判定していません。

mode3の文字は原本では見えません。破線は構造の説明用です
mode3の文字は原本では見えません。破線は構造の説明用です(説明用概念図)

条件は同じページで「空白以外の抽出文字>0」「raster画像描画>0」「mode3のテキスト描画>0」が揃うこと。透明度、白文字、細工された重ね合わせを全て検出する条件ではありません。mode4–7のclipping描画はmode3と別集計です。

主要11条件の測定結果

以下の数値は文書内のページ合計です。raster画像描画はPDF.jsの画像描画命令数であり、ユニークな実画像の個数ではありません。文字数は空白を除いた抽出文字数です。

条件抽出文字(空白除外)raster画像描画不可視文字描画Tool判定
通常テキスト500テキスト中心
画像のみ010画像中心・抽出テキストなし
画像+可視テキスト510画像と抽出テキストが混在
画像+不可視テキスト(OCR風)511画像と抽出テキストが混在(OCR候補 1ページ)
同位置の二重文字1000テキスト中心
別位置の同じ単語1000テキスト中心
ページ外候補1100テキスト中心
Unicode候補400テキスト中心
0 / 90 / 180 / 270°回転2000テキスト中心
vector図形のみ000抽出テキストなし
6ページ混在2532テキスト中心/画像と抽出テキストが混在/画像中心・抽出テキストなし(OCR候補 2ページ)
条件重複グループページ外項目Unicode文字
通常テキスト000
画像のみ000
画像+可視テキスト000
画像+不可視テキスト(OCR風)000
同位置の二重文字100
別位置の同じ単語000
ページ外候補010
Unicode候補004
0 / 90 / 180 / 270°回転000
vector図形のみ000
6ページ混在000

同じ文字でも、同位置の重なりだけが重複候補

同位置にHELLOを2回描いた条件は、抽出文字10・重複候補1グループ。別位置のHELLOを2回描いた条件は、抽出文字10・重複候補0でした。三重文字も1つの連結グループになります。影や縁取り、意図した重ね文字でも候補になるため、「二重OCR」と断定できません。

同位置の二重文字は1グループ、離れた同じ単語は0
同位置の二重文字は1グループ、離れた同じ単語は0(説明用概念図)

現行条件は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では、候補ページを原本と見比べる

  1. PDFを選び、抽出文字のないページやOCR候補を確認します。
  2. 重複・ページ外・Unicode候補のページを開き、文字枠と原本を照らします。
  3. 実際に使うビューアで、必要な文字の検索とコピーを確認します。

自分のPDFの文字レイヤーを確認する

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.pdf1テキスト中心100000通常テキスト
b-image-only.pdf1画像中心・抽出テキストなし010000画像のみ
c-visible-image.pdf1画像と抽出テキストが混在110000画像+可視テキスト
d-ocr-like.pdf1画像と抽出テキストが混在(OCR候補 1ページ)111000画像+不可視テキスト(OCR風)
f-duplicate.pdf1テキスト中心200100同位置の二重文字
g-separate.pdf1テキスト中心200000別位置の同じ単語
h-outside.pdf1テキスト中心100010ページ外候補
i-small-bleed.pdf1テキスト中心1000001ptのはみ出し。2pt余白内のため候補0
j-unicode.pdf1テキスト中心300004Unicode候補
l-vector.pdf1抽出テキストなし000000vector図形のみ
m-triple.pdf1テキスト中心300100同位置の三重文字。連結した1グループ
q-form.pdf1テキスト中心201100Form内の不可視文字。画像なしのためOCR候補ではない
r-save-restore.pdf1テキスト中心302000save/restoreをまたぐ描画モード
s-clip.pdf1テキスト中心100000mode7のclipping描画1。不可視mode3と別集計
e-mixed.pdf6テキスト中心/画像と抽出テキストが混在/画像中心・抽出テキストなし(OCR候補 2ページ)5320006ページ混在
k-rotations.pdf4テキスト中心4000000 / 90 / 180 / 270°回転
n-20-pages.pdf20テキスト中心2000000通常テキスト20ページ
n-100-pages.pdf100テキスト中心10000000通常テキスト100ページ
o-password.pdf1パスワード付きPDFには対応していません。000000意図したパスワード拒否
p-malformed.pdf取得不能PDFを解析できませんでした。破損または対応外のPDFの可能性があります。000000意図した破損PDF拒否
sample.pdf4テキスト中心/画像中心・抽出テキストなし/画像と抽出テキストが混在(OCR候補 1ページ)421100通常・画像・OCR風・二重文字の公開サンプル
測定時の実装と再現方法

測定元commit:82029598bcffba31b591d57e9ccf0ff489c493f3。現行ToolのanalyzeBytesを直接使用しています。

  1. node scripts/measure-pdf-text-layer-article.mjs
  2. python scripts/package-pdf-text-layer-article.py
  3. node scripts/render-pdf-text-layer-article.js

測定元のTool本体 · 判定ロジック · 既存fixture生成script