PDF 構文 ファイル構造 (各部)

PDF構文 (PDF Syntax ISO 32000-1)

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

2.PDFファイル構造 ‐各部‐

PDFのデータ構造は、以下のように4つの部分(ヘッダーボディークロスリファレンス・テーブルトレイラー)で構成されています。

ヘッダー
(Header)
ボディー
(Body)
クロスリファレンス テーブル
(Cross-reference Table)
トレイラー
(Trailer)
ただし、この構造はPDFが最初に作成されたときの構造です。
PDFはその内容をあとから変更(追加更新「Incremental Update」といいます)できるようになっています。更新されたPDFでも左図の構造が基本になります。
ここでは、説明のために初期状態のPDF構造を利用します。

2.1 ヘッダー (Header)

PDFファイルの第1行目にあるデータで、そのバージョンを表しています。以下のようなものです。

%PDF-1.N
指定されたPDFファイルのバージョン(先頭に記載)を解析します。
(このブラウザでは機能しません。)

Nには、0,1,2,3,4,5,6,7 のいずれかの数値が入ります(%PDF-2.0と記載された場合もあります)。 最初の文字"%"はそれに続く文字列がコメントであることを示しています。 しかし、この行は特殊の意味を持っていてPDF文書のバージョンを表します。 「PDF文書のバージョン」の意味するところは「PDF文書を構成するPDF構文のシンタックスバージョン」です。

なお、PDF1.7(ISO 32000-1)は、それ以前のバージョンのPDFデータをすべて解釈できる規格です。
PDF2.0(ISO 32000-2)も同様です。

ご注意ください: ここで示されたバージョンはPDF文書の更新によっ更新される場合があります(PDF1.4以上)。 その場合の新しいバージョンはカタログ ディクショナリトレイラーのRoot項目で示される)で示されます。

2.2 ボディー (Body)

文書の内容を表す、以下のようなインダイレクト・オブジェクト(PDFを構成する名前付きオブジェクト)で構成されています。
内容は、F1フォントで50ポイントの文字“Hello World”を位置(100,600)に表示することを示したインダイレクト・オブジェクトの例です。

5 0 obj
<< /Length 43 >>
stream
BT /F1 50 Tf 100 600 Td (Hello World) Tj ET
endstream
endobj

オブジェクトにはbooleannumber(整数/実数)、string(文字列)、namearray(配列)、dictionary(辞書)、Stream(ストリーム)、null の8種類があります。
特に、dictionaryには上記のようにstreamを付加できます。 streamが付加されたオブジェクトをストリーム オブジェクトといいます。

インダイレクト・オブジェクト
名前付きオブジェクト(Named Object)ともいいます。
インダイレクト・オブジェクトは、上記の例のように正整数と非負整数の2っで識別されます(「5 0 obj」の部分)。 最初の正整数はオブジェクト番号で、その番号は順に割り当てられます。しかし、オブジェクト自身が記載される順番は番号順ではありません。

オブジェクト番号に続く非負整数は世代番号です。 最初に生成されたインダイレクト・オブジェクトの世代番号は0(ゼロ)で、そのオブジェクトが更新されると世代番号が増数されます。

インダイレクト・オブジェクトは、正整数と非負整数の組み合わせで一意に識別されます。 また、その識別番号(ラベルともいいます)を使って他のインダイレクト・オブジェクトから参照することもできます。

インダイレクト・オブジェクトを参照
あるオブジェクトから他のインダイレクト・オブジェクトを参照する場合はオブジェクト番号と世代番号の組み合わせにキーワード“R”をつけてインダイレクト・オブジェクト指定します。

以下の例では5 0 のオブジェクトが6 0 のオブジェクトを参照しています。 (5 0 オブジェクトは6 0 オブジェクトを使って、43バイトのストリームを持つことを表しています。)

5 0 obj
<< /Length 6 0 R >>
stream
BT /F1 50 Tf 100 600 Td (Hello World) Tj ET
endstream
endobj

6 0 obj
  43
endobj

2.3 クロスリファレンス・テーブル (Cross-reference Table)

クロスリファレンス・テーブルは、キーワード"xref"が記載された行から開始します。

PDFのボディ部にあるインダイレクト・オブジェクトをランダムにアクセスするため、それらがどの位置(オフセット“Offset”といい、PDFデータの先頭からのバイト位置です)にあるかを表したテーブルです。

このセクションの書式は固定です。 各行に記載される情報の区切り文字はスペース(ASCIIの0x20)でなければなりませんし、クロスリファレンスの各行は必ず2バイトの行末コードで終了します。 ここでの行末コードは、0x0D0A、0x0D20、0x0A20のいずれかです。

以下は、クロスリファレンス・テーブルの例です。

xref
0 8
0000000000 65535 f
0000000017 00000 n
0000000376 00000 n
0000000117 00000 n
0000000266 00000 n
0000000544 00000 n
0000000447 00000 n
0000000610 00000 n
指定PDFファイルのxrefを解析します。
(このブラウザでは機能しません。)

2行目からがクロスリファレンス サブセクションです。

クロスリファレンス サブセクション
クロスリファレンスのサブセクションはそのセクションに記載されるオブジェクト番号の範囲を示す行で開始されます。 その行には2種類の数値が含まれています。 1番めの数値は、そのサブセクションに含まれている最初のオブジェクト番号で、2番めの数値はオブジェクトの数量です。
上記例の「0 8」はオブジェクト番号0から7までの8個のオブジェクトのクロスリファレンスが記載されていることを示しています。
オブジェクト範囲を示した行に続くのがクロスリファレンス自身です。

クロスリファレンス
ひとつのクロスリファレンスは、行末コードを含めて20バイトで以下のように構成されています。

nnnnnnnnnn ggggg n

「nnnnnnnnnn」は10桁の数値でそのオブジェクトが配置されたオフセット位置を示しています。 「ggggg」は5桁の数値でオブジェクトの世代番号を示します。 「n」は“使用中”を表します。 各クロスリファレンスは、2バイトの行末コードで終了します。

使わなくなったオブジェクトのクロスリファレンス
更新(削除や変更)によって使われなくなったオブジェクトのクロスリファレンスもクロスリファレンス・テーブルにリストされます。 そのオブジェクトのクロスリファレンスはキーワード「f」が以下のように使用されます。

nnnnnnnnnn ggggg f

なお、この場合の「nnnnnnnnnn」は次の使わなくなった(フリーな)オブジェクトのオブジェクト番号を示します(詳細は、オブジェクト番号0参照)。 使われなくなったインダイレクト・オブジェクト更新によって削除されることはありません。 そのため、このインダイレクト・オブジェクトは更新前のクロスリファレンス テーブルを使えばいつでも参照できます。

オブジェクト番号0 (フリーなインダイレクト・オブジェクト)
オブジェクト番号0のオブジェクトは常に使わなくなった(フリーな)オブジェクトを表します。 世代番号もその最大値である65535を示しています。 複数の使わなくなったオブジェクトがクロスリファレンスにある場合は、以下のようになります。

xref
0 6
0000000003 65535 f
0000000017 00000 n
0000000081 00000 n
0000000000 00007 f
0000000331 00000 n
0000000409 00000 n

オブジェクト0はその次にフリーなオブジェクトの番号が3であることを示しています(オブジェクト3にリンクしているといいます)。 オブジェクト3が示しているのはオブジェクト番号0なので(オブジェクト0にリンクしているので)これ以上のフリーなオブジェクトが(現在の)PDF文書に無いことがわかります。 またその行の世代番号は次に生成するべきインダイレクト・オブジェクトの番号が7であることを示しています。
なお、フリーなオブジェクトを表すもうひとつの形式があります。フリーなオブジェクトは必ずオブジェクト0にリンクし世代番号を65535とする形式です。

2.4 トレイラー (Trailer)

トレイラーはクロスリファレンス・テーブルと特殊なオブジェクトを読み取るためのものでPDFファイルの最後に置かれています。 PDFファイルの最後は必ず以下のように「trailer」、「startxref」、「%%EOF」がこの順で出現しなければなりません。

trailer
<<
/Size 8
/Info 6 0 R
/Root 7 0 R
/ID [<1775615b6d180ff72f4473d56aaa72bf><1775615b6d180ff72f4473d56aaa72bf>]
>>
startxref
665
%%EOF
指定PDFファイルの"trailer"を解析します。
(このブラウザでは機能しません。)

PDFファイルの最終行は「%%EOF」です。 その前2行には"startxref"キーワードと数値それぞれを記載した行が順にあります。 この数値はxref(クロスリファレンス)セクションが記載されている位置を示すオフセット値(PDFファイル先頭からのバイト位置)です。
さらに、startxrefの前には"trailer"キーワードで示されたトレイラー(trailer)ディクショナリーがあります。 ディクショナリーとは、「<<」と「>>」で囲まれてキーと値の組が含まれたものです。
以下は、トレイラーに記載されるキー項目です。

キー
Sizeクロスリファレンス・テーブルのエントリ数
Prev以前のクロスリファレンス・テーブルの位置を示すオフセット値
Rootカタログ(Catalog)ディクショナリ
Encrypt暗号化ディクショナリ
Info文書情報(Document Information)ディクショナリ
ID2っのバイトストリング(「<」と「>」で囲まれた)で構成されたファイル識別子

以前のクロスリファレンス・テーブル
PDFの更新とはデータを「書き換える」のではなく、「変更部分をPDFデータの最後に追加」することによって更新します。 そのため、更新前のクロスリファレンス・テーブルが削除されずにPDF内部に残されその意味も失いません。
更新前のクロスリファレンス・テーブルのオフセット値はトレイラーのPrev要素として記載されます。

カタログ(Catalog)ディクショナリ
トレイラーのRoot項目にあるカタログ ディクショナリは、PDFオブジェクト階層のルートです。 このディクショナリは文書の内容、しおり、記事のスレッド、名前の付いた(文書内の)リンク先および他の属性を示すオブジェクトのリファレンスさらに、PDF文書がどのように表示されるか(しおりやサムネール画像を表示するか、最初に表示するページなど)を示す情報が含まれています。
このカタログ ディクショナリの詳細は「ドキュメント カタログ」を参照してください。

暗号化(Encrypt)ディクショナリ
パスワードや電子証明書を使ってPDF文書が暗号化されていることが示されます。 その場合は暗号化ディクショナリに暗号化の詳細情報が記載されます。
このディクショナリがPDF文書内に存在していない場合はPDF平分(非暗号化)文書です。

文書情報(Info)ディクショナリ
PDF文書のメタデータのひとつです。以下の情報が含まれます。

キータイプ
Titletext string文書のタイトル
Authortext string文書を作成した人の名前
Subjecttext string文書のサブジェクト
Keywordtext string文書に関するキーワード
Creator text stringPDF以外の形式から変換した場合に、そのオリジナルの作成ツール
Producertext stringPDF以外の形式から変換した場合に、その変換ツール
CreateDate日付文書が生成された日時(人が読める形式)
ModDate日付文書が更新された最終の日時
Trappedname文書がトラッピング情報を含むように変更されたかどうかを示す
名前オブジェクト

オブジェクトのタイプは「2.5オブジェクト」を参照してください。

文書情報ディクショナリの例を以下に記します。

1 0 obj
<< /Title (PDF Imager-LP Reference)
/Author (Trust Software System)
/Creator (PDF Imager-LP)
/Producer (Trust Software System, PDF Imager-LP)
/CreationDate (D:20170215010203+09'00')
/ModDate (D:20170216040506+09'00')
>>
endobj

ID - ファイル識別子
PDFファイルを識別するユニークなバイト列です。

2.5 オブジェクト (Object)

オブジェクトには、8種類(booleannumberstringnamearraydictionarystreamnull)の基本的なタイプがあります。 また、オブジェクトにはラベルの付いたものとそうでないものがありラベルの付いたオブジェクト(インダイレクト・オブジェクトといいます)は他のオブジェクトが参照することができます。

boolean
真偽値をキーワードの"true"または"falase"で表します。 これらはarrayもしくはdictionaryの項目として利用できます。 また、PostScriptの計算の戻り値としても利用されます。

number - integer(整数)とreal(実数)
数値の整数と固定小数点の実数を表します。 数値の値や精度の制限は以下のように規定されています。

integer-2,147,483,648 から 4,147,483,647 まで
real±3.403x1038(最大・最小値)、
±1.175x10-38(0ではない一番小さな値)、
5(精度、小数点以下の桁数)

以下にinteger及びrealの例を示します。

123  43445  +17 -98 0

34.5  -3.62  +123.6  4.  -.002  0.0

string
stringは、バイトデータの並びを表現します。いわゆる文字列データ(literal string)やバイナリーデータ(hexadecimal string)を表します。文字列データは、"( )"で囲み以下のように表します。

(This is a string)
(Strings may contain newlines
and such.)
(日本語文字列)

バイナリーは、数字の0から9とAからFまたはaからfで表し"<"と">"で囲み以下のように表します。

<4E6F762073686D6F7A206B6120706F702E>
<901FA3>
<901FA>
<901FA0>

ご注意ください。バイナリーの桁数が偶数でない場合は、0が補充されて解釈されます。そのため、上記の例で最後の2行は同じバイナリーデータを表します。
stringは、その長さが32,767バイトまでと規定されています。

name
nameは、NULL以外のASCII文字を連続して並べたものです。先頭に"/"(スラッシュ)を付けて表します。以下に例を示します。

/Name1
/ASomewhatLongerName
/A;Name_With−Various***Characters?

nameの最大長さは、127バイトと規定されています。

array
arrayは、1次元の配列でその並び順に意味があるものです。PDFのarrayは、その項目に他のオブジェクトを含めることができます。arrayは、"["と"]"で囲み以下のように表します。

[549 4.14 false (Ralph) /SomeName]

dictionary
dictionaryは、キーと値のペアを要素としたものです。dictionaryの要素数は0個でもかまいません。dictionaryは、"<<"と">>"で囲み以下のように表します。

<< /Type /Example
   /Subtype /DictionaryExample
   /Version 0 . 01
   /IntegerItem 12
   /StringItem ( a string )
   /Subdictionary << /Item1 0 . 4
                     /Item2 true
                     /LastItem ( not ! )
                     /VeryLastItem ( OK )
                  >>
>>

stream
streamは、バイトのデータが直接記載されたものです。PDFアプリケーションはこのデータを直接バイトデータとして順に読み取ります。
また、そのサイズに(アプリケーションの実装上の制限以外に)制限はありませんので、streamには大きなデータや画像などのデータを格納できます。
streamはdictionaryに続けて、キーワード"stream"と"endstream"で囲んで記載します。

dictionary
stream
...0個以上のバイトデータ...
endstream

null
nullは、他のどのオブジェクトにも等しくない、正にヌルのオブジェクトです。"null"で表します。

2.6 ストリーム オブジェクト (Stream Object)

dictionaryタイプのインダイレクト・オブジェクトにはストリーム(Stream)を付加できます。このストリームが付加されたオブジェクトを、ストリーム オブジェクトといいます。
ストリームには、大きなサイズのバイトデータ(画像データや描画用のデータ)を格納できます。多くの場合、このバイトデータは圧縮されています。
ストリームは、ディクショナリ オブジェクトでなければならず、そのディクショナリ オブジェクトはLength項目を含まなければなりません。この項目は、ストリームのバイトサイズ(データが圧縮されている場合は、圧縮されたデータのバイト数)を表します。
以下は、ストリーム オブジェクトの例です。

3 0 obj
<< /Filter /FlateDecode /Length 72 >>
stream
... 72バイトのバイナリデータ...
endstream
endobj

このオブジェクトは、72バイトのストリーム データを含み、そのデータはFlateDecodeで圧縮されていることがDictionaryに示されています。

ストリーム(Strem) オブジェクト ディレクトリの項目
ストリーム(Strem) オブジェクトのディクショナリには、以下の項目が追加されます。

キータイプ
Lengthinteger(必須)ストリーム(Stream)に記載されたデータのバイト数
Filtername /
array
(オプション)ストリーム データが圧縮された場合のフィルター名
複数フィルターの場合はarrayで記載
DecodeParmsdictionary /
array
(オプション)フィルターのパラメータを指定

オブジェクトのタイプは「2.5オブジェクト」を参照してください。


ご質問 ・ お問い合わせ

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


PDF Toolsライト

PDF 構文解説

(ISO32000-1より)

PDF Tools製品概要