# PDFの構造 PDFは4つのデータ構造で構成される。 | 名前 | 説明 | |-----------------------------------------------------------|----------------------------------------| | [ヘッダー](#ヘッダ) | バージョンを指定 | | [ボディー](#ボディー) | PDFの内容 | | [クロスリファレンステーブル](#クロスリファレンステーブル) | ボディーのオフセット | | [トレイラー](#トレイラー) | クロスリファレンステーブルのオフセット | ## ヘッダー ヘッダーにはPDFのバージョンを指定する。 最初の行が``%PDF-m.n``で始まる必要がある。m.nはPDFのバージョンである。 ``` %PDF-1.7 %🍣 ``` PDFファイルにはバイナリデータが含まれるため、ヘッダー行の直後に4バイト以上のバイナリ文字(0x80以上)のコメント行があることが望ましい。 🍣はU+1F363であり、UTF-8では``F0 9F 8D A3``となる。(4バイト以上のバイナリ文字であればなんでもよい) ## ボディー 間接オブジェクト(indirect object)が並んでいる。 ``オブジェクト番号 世代番号 obj``で始まる。 オブジェクト番号は正の整数で連番であることが多い。 世代番号は正の整数で、PDFが後から更新された際に追加されることがある。 以後、世代番号は0固定であるものとして説明する。 ``obj ~ endobj``の間がオブジェクトの内容になる。 特別な場合を除き``<< xxx >>``という辞書形式のみを説明する。 ``` % オブジェクト番号123、世代番号0、辞書データを持つ 123 0 obj << /Type /Page >> endobj ``` ストリームデータを持つ場合は``stream ~ endstream``の間に記述する。 ``/Length``の指定は必須である。 ``` % オブジェクト番号234、世代番号0、ストリームデータを持つ 234 0 obj << /Length 49 >> stream BT /F1 50 Tf 10 20 Td (Text Data) Tj ET endstream endobj ``` ## クロスリファレンステーブル ランダムアクセスを可能にするため、間接オブジェクトのオフセットを記録する。 xrefの次行に``開始オブジェクト番号 個数``を記述する。 その後にエントリとして個数分のオブジェクトへのオフセットを記述する。 オブジェクト番号0番は常に空きであり、世代番号は65535固定になるため``0000000000 65535 f``となる。末尾のfは空きを表す。 その後、オブジェクト番号1番から``nnnnnnnnnn ggggg n``の形式で指定する。 nnnnnnnnnnは10桁のオブジェクト番号、gggggは5桁の世代番号、nは使用中であることを表す。 エントリは1行20バイトでなければならない。[^CrossReferenceEntry] ``nnnnnnnnnn ggggg n``の形式が18バイトになるため、2バイトの改行コードを使用するか、スペース1バイトと1バイトの改行コードを使用する必要がある。 [^CrossReferenceEntry]: エントリが20バイトでないとPDFリーダーでは正しく読み込めないことがある。Adobe Acrobatでは表示できるが閉じる際に保存を促された。 ``` xref 0 4 0000000000 65535 f 0000000016 00000 n 0000000070 00000 n 0000000136 00000 n ``` PDFを後から更新すると、エントリの後に再度``開始オブジェクト番号 個数``とエントリが出現することがある。 本説明ではこの形式は説明しない。 ## トレイラー trailerに続いて辞書形式で設定する。 startxrefの次行にクロスリファレンステーブルへのオフセットを指定する。 最終行は%%EOFで終了する。[^EOF] [^EOF]: Adobe Acrobatではファイル末尾から1024バイト以内に%%EOFが必要とのこと。 | キー | 型 | 説明 | |---------|--------------------------------------|-------------------------------------------------------------------------------------------------| | Size | integer(間接参照不可) | 必須、クロスリファレンステーブルのエントリ総数 | | Root | dictionary(間接参照でないといけない) | 必須、カタログタイプへの間接参照 | | Info | dictionary(間接参照でないといけない) | 任意、ドキュメント情報への間接参照 | | Encrypt | dictionary | 任意、[暗号化](暗号化)の際は必須 | | ID | array | 任意、ファイル識別子となる要素が2のバイト配列、[暗号化](暗号化)のにID自体は暗号化してはいけない | ``` trailer << /Size 4 /Root 1 0 R >> startxref 1234 %%EOF ``` ## オブジェクトの種類 PDFでは次のオブジェクトがサポートされる。 | タイプ | 説明 | |-----------------|---------------------------------------------------------------------------------------------| | Boolean | 真偽値、true または false(アルファベット小文字) | | Integer | 整数、上限・下限はアプリケーション依存 | | Real Number | 実数、上限・下限はアプリケーション依存 | | String | 文字列、``( xxx )``形式のリテラル文字列、``<0000>``形式の16進文字列 | | Name | 名前、``/Name``形式 | | Array | 配列、配列内には任意のオブジェクトが格納できる、``[ xxx ]``形式 | | Dictionary | 辞書、キーと値のペア、``<< /Key /Value >>``形式 | | Stream | ストリーム、``<< /Length xxx >> stream ~ endstream``形式、間接オブジェクトである必要がある | | Null Object | null値 | | Indirect Object | 間接オブジェクトの参照、``オブジェクト番号 世代番号 R``形式 | リテラル文字列内では不均衡なカッコとバックスラッシュ以外が使用できる。 次のエスケープシーケンスを使用できる。 | シーケンス | 説明 | |------------|----------------------------| | \\n | ラインフィード(LF) | | \\r | キャリッジリターン(CR) | | \\t | 水平タブ(HT) | | \\b | バックスペース(BS) | | \\f | フォームフィード(FF) | | \\( | 左カッコ | | \\) | 右カッコ | | \\\\ | バックスラッシュ | | \\ddd | キャラクターコード(10進数) | 名前はスラッシュで始めてスペースを含めることはできない。 大文字、小文字は区別される。 名前中にスペースなどを入れる場合は、``#00``形式で埋め込むことができる。 ``` /Adobe#20Green %→Adobe Green /PANTONE#205757#20CV %→PANTONE 5757 CV /paired#28#29parentheses %→paired()parentheses /The_Key_of_F#23_Minor %→The_Key_of_F#_Minor /A#42 %→AB ```