PDFをパースしたいですか?
(eliot-jones.com)- PDFパースは明確な順序と構造に基づいて動作すべきですが、実際のファイルはこの規格に従っていないことがよくあります
- cross-reference(xref)ポインタやオフセット探索では、さまざまなエラーや不一致が発生します
- 実際には、PDFヘッダー前の不要なデータや、ポインタ・オフセットの誤った位置によって多くの問題が生じます
- PDFのxrefテーブル自体が不明確または誤った形式になっているケースも多くあります
- そのため主要なビューアは、非標準のPDFファイルまでサポートするロジックを追加実装しています
PDFパースへの理想的なアプローチ
- PDFパースは理論上、一定の手順で進みます
- ファイル先頭でバージョンヘッダーのコメントを探す
- cross-reference(xref)ポインタを探す
- すべてのオブジェクトオフセットを収集する
- trailer辞書を見つけて、全体のカタログ構造にアクセスする
PDFオブジェクトの紹介
- PDFオブジェクトは、数値、文字列、辞書などのさまざまなPDF要素を包んで保存する単位です
- 各オブジェクトは「
obj/endobj」マーカーの間に存在します - オブジェクト同士は、**間接参照(indirect reference、例:
16 0 R)**の方式で接続されます - ファイル内でのオブジェクト分割方法は自由ですが、一部のオブジェクト型は必ず間接参照でなければなりません
cross-referenceオフセットを探す
- PDFには構造上、cross-reference(xref)テーブルがあり、これはオブジェクト位置のインデックスとして機能します
- ファイル末尾には
startxref構文で特定のバイト位置がポインタとして示されます - このポインタがxref位置を指定しますが、仕様と実際のファイルには差異があります。たとえば
%EOFマーカーは本来最後の行にあるべきですが、実際のPDFでは末尾1,024バイト以内のどこにあってもおかしくありません - 実際のファイルでは、ポインタの書式ミス(
startrefなど)や改行欠落など、さまざまな変形が見つかります
オブジェクトオフセットを探す
- xrefテーブルは
xref、オブジェクト開始番号、オブジェクト数が順に続き、各オブジェクトのオフセット/生成番号/状態(nまたはf)が1行ずつ記録されます - xrefテーブルが複数ある場合や、
/Prevエントリで相互に連結されている場合もあります
trailer辞書の位置を探索する
startxrefマーカーの上部にはtrailer辞書があり、ルートオブジェクトを見つけるための必須メタデータが含まれます- ルートオブジェクトを基準に、全体構造の解釈を開始できます
実環境: 予期しない問題点
-
PDF仕様に準拠していないファイルが多く、一般的なパーサでは処理が困難です
-
cross-referenceポインタ探索でよく失敗するケース
- ポインタがファイル末尾、または最後の1,024バイト以内にない
- タイポ(
startrefなど) - 例外的な形式
-
実際のPDFサンプル3,977件の調査では、約0.5%がxref宣言エラーを持っていました
PDFコンテンツが0以外のオフセットで始まる
- ヘッダー前に**不要データ(junk)**があると、すべてのバイトオフセットがずれて
startxrefの位置も食い違います - ヘッダー位置を基準にオフセットを再計算する必要があり、両方の位置を確認しなければなりません
- 全体のエラーの約50%を占めます
xrefポインタがxrefテーブルの途中を指している
- 指定オフセットがxrefテーブル内容のちょうど中ほどを指してしまうことがあります
- 3,977件のサンプル中、約5件で見つかりました
ポインタがxrefの近くにある
- ポインタが正確ではなくても、xrefの直前または直後の空白や改行文字のずれ程度にとどまることがよくあります
ポインタは正しいがxrefオフセットが間違っている
- xref表に記録されたオフセット自体が誤っていることもあります
- 一部のオブジェクトだけが正しく、残りはオフセットエラーを持つ場合もあります
最初のポインタは正常だが以前のオフセット(/Prev)がおかしい
- PDFを修正して生成される**
/Prevポインタ**に誤った値(例:0)が保存されている例が多数あります
xrefテーブルの形式が異常である
- 改行なしで
xrefと数字が連結されていたり、宣言されたオブジェクト数より多くの項目があったり、表の途中にゴミデータが含まれていたりと、さまざまな形で現れます - こうしたケースは PdfPig などでも issue として多数報告されています
結論
- 仕様上、PDFパースは定型的な手順で処理されるべきですが、実際のファイルの多くはそうではなく、パースにはさまざまな問題が生じます
- 実用PDFビューアは、非規格PDFへの対応拡張機能を標準で備えています
- 今回の要約は、PDF仕様(全1,300ページ中22ページ分)に相当する一部分のパースだけを扱っています
まだコメントはありません。