PDF 構文 ファイル 解析手順

PDF構文 (PDF Syntax ISO 32000-1)

PDF1.7はISO技術委員会によって2008年1月に“ISO 32000-1規格”として承認され、 2017年7月にはPDF2.0の規格ISO3200-2が承認され、2020年12月にはこの規格は第二稿になりました。
ここでは32000-2規格で説明されているPDF1.7の構文(構造)について説明しています。
PDFファイルは8-bitデータを単位として構成されていて一般の文書編集アプリケーションで開くことができその内容を読取ることができます。ただし、バイナリのデータもそのまま(表示可能な文字に変換されずに)格納されていますので文字化けしているように表示されますが、これはPDFの仕様です。
ここではそのデータの一部を読み解くことでPDF文書へのデータ追加などPDF再構成の意味を説明しPDF-ToolsでのPDFデータ解析や編集をより詳細にできるようにします。

0.PDFファイル 解析手順

PDFデータは1バイト(8ビット)のシーケンスで構成されています。 このシーケンスを複数のASCII文字で構成されたバイトデータの組み合わせ(キーワード)として解析します。
なお解析手順はHelloWorld.pdfを使って説明します。

このPDFはダウンロード、または表示できます。
ダウンロードしたPDF文書を通常のエディタで開くとその内容を見ることができます。

PDF構造の概要は、こちらを参照してください。

0.1 PDFファイルを通常のエディターで開く

PDFデータを通常のエディターで開くとHelloWorld.pdfデータのように表示されます。

ただしPDFデータのバージョンなどによっては、クロスリファレンステーブルが圧縮データ(クロスリファレンス ストリーム)で格納されていて文字化けしたように見える場合がありますので注意してください。

0.2 PDFファイル終端を探す

PDFファイルは以下の「%%EOF」の行で終端されます。

%%EOF

ただし、この行以降に文字などのデータがあっても無視される仕様ですので「%%EOF」の行は必ずしもファイルの最後ではありません。

0.3 クロスリファレンス テーブルへのオフセット値

「%%EOF」行の直前2行には以下のように「startxref」キーワードが記載された行と数字だけが記された行が必ずあります。

startxref
609
%%EOF

この数値はファイルの先頭からのバイト数を表していて、その位置にクロスリファレンスを表す「xref」キーワードが記載されていることを示しています。
ただし、PDF 1.5以上でクロスリファレンス ストリームを含む場合はこの限りではありません。

PDF Imager-LP無償版)でクロスリファレンステーブルの位置(オフセット)を表示するソースコード

C# C/C++ Python
全体のソースコード

0.4 トレイラー ディクショナリ

「startxref」行の前には以下のように「trailer」キーワードが記載された行に続いて、ディクショナリ(「<<」と「>>」で囲まれキーと値のペアが複数個内包されたもの)があります。
PDFファイル終端の一般形は以下のとおりです。

trailer
  << key1 value1
     key2 value2
     ...
     keyn valuen
  >>
startxref
Byte_offset_of_last_cross-reference_section
%%EOF

以下は、その具体例です。見やすいように改行してあります。

trailer
  <<
    /Info 2 0 R
    /Root 1 0 R
    /Size 8
    /ID [<1775615b6d180ff72f4473d56aaa72bf><a5902498ce444a8aa67f819e1023432d>]
  >>
startxref
609
%%EOF

このtrailerディクショナリ(詳細は「2.4トレイラー(trailer)」を参照してください)にはPDFを構成するオブジェクト ツリーのルートやPDFの概要が記されたオブジェクトへの参照が示されています。
PDFデータを解析する場合はまずルートオブジェクトを探します。
このPDF文書の場合は、Rootキーとペアとなる値「1 0 R」がルートオブジェクトです。

PDF Imager-LP無償版)でトレイラーを表示するソースコード

C# C/C++ Python
全体のソースコード

0.5 ルート オブジェクト

ルート(Catalog) オブジェクトを探すにはTrailerの「/Root」キーからたどります。
HelloWorld.pdfの場合は番号1のオブジェクトがそれにあたります。 以下がそのオブジェクトです、見やすいように改行してあります。

1 0 obj
  <<
    /Pages 3 0 R
    /Type /Catalog
  >>
endobj

このディクショナリの「/Pages」で示されたオブジェクト(複数の場合があります)からPDF各ページのコンテンツ(内容)が記載されたオブジェクトをたどれます。

PDF Imager-LP無償版)でルート(Catalog) オブジェクトを表示するソースコード

C# C/C++ Python
全体のソースコード

0.6 ページ・ツリー オブジェクト

HelloWorld.pdfのルートオブジェクトからたどったページツリーオブジェクトは以下のとおりです。見やすいように改行してあります。

3 0 obj
  <<
    /Count 1
    /Kids [ 4 0 R ]
    /Type /Pages
  >>
endobj

この記述からこのPDF文書は全1ページ("/Count")で構成されていて、そのページの情報("/Kids")が4番目のオブジェクトに記載されていることがわかります。

PDF Imager-LP無償版)でPageTreeディクショナリーを表示するソースコード

C# C/C++ Python
全体のソースコード

0.7 ページ オブジェクト

HelloWorld.pdfのページツリーからたどったページ オブジェクトは以下のとおりです。見やすいように改行してあります。

4 0 obj
  <<
    /Contents 5 0 R
    /MediaBox [ 0 0 595 842 ]
    /Parent 3 0 R
    /Resources 6 0 R
    /Type /Page
  >>
endobj

ここから、このページの大きさ("/MediaBox")は幅が595高さが842であることがわかります。
さらにページの内容("/Contents")が5番目のオブジェクトに記載されていることがわかります。

PDF Imager-LP無償版)でPageオブジェクトとContentsオブジェクトを表示するソースコード

C# C/C++ Python
全体のソースコード

0.8 ページコンテンツ オブジェクト

HelloWorld.pdfのページのページコンテンツ オブジェクトは以下のとおりです。

5 0 obj
<< /Length 75 >>
stream
BT
1 0 0 1 100 600 Tm
/SF1 50 Tf
0 Ts 0 Tr 0 Tc 0 Tw
(Hello, World.) Tj
ET
endstream
endobj

ここにあるデータは圧縮されていないので、その内容を見ることができます。
この描画コマンドは"Hello, World."という文字列を指定のフォント(7 0 objで指定されたHelvetica)と大きさ(50ポイント)で指定の位置に描画します。

PDF Imager-LP無償版)でページコンテンツを表示するソースコード

C# C/C++ Python
全体のソースコード

>>>「PDF 構造 -概要-

ご質問 ・ お問い合わせ

 メールで support@TrustSS.co.jp 宛てに、または 質問のページからお送りいただくようお願いします。
ご要望も受け付けております。


PDF Toolsライト

PDF 構文解説

(ISO32000-2より)

PDF Tools製品概要