トラスト・ソフトウェア・システム
ホーム > PDF Tools トップ > PDF Tools ライト > PDF 構文

PDF構文 (PDF Syntax ISO 32000-1)

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

PDF ファイル構造 -概要-」へ <<< >>>「PDF 構造 テキスト」へ


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

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

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

PDF文書の構造解析を支援するライブラリ PDF Easy Parserはこちらです。
このツールを用いると、クロスリファレンスや、各オブジェクト(または、それらの要素)を容易に取り出せます。


2.1 ヘッダー (Header)

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

%PDF-1.N

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

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


C++でPDF文書のバージョンを取得するサンプルコード


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


PDF Easy ParseでPDF文書の最新のバージョンを取得する


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(整数/実数)、stringnamearraydictionaryStreamnull の8種類があります。
特に、dictionaryには上記のようにstreamを付加できます。付加したオブジェクトをストリーム オブジェクト(2.6 ストリーム オブジェクト参照)といいます。


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


オブジェクト番号に続く非負整数は、世代番号です。最初に生成されたインダイレクト・オブジェクトの世代番号は0で、そのオブジェクトが更新されると世代番号が増数されます。最近のPDF文書では、ほとんどの場合で世代番号に0以外が指定されなくなりました。


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


PDF Easy Parseでインダイレクト・オブジェクトを取得するサンプル解析の結果


インダイレクト・オブジェクトを参照
あるオブジェクトから他のインダイレクト・オブジェクトを参照する場合は、オブジェクト番号と世代番号の組み合わせにキーワード“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

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


PDF Easy Parseでクロスリファレンスを取得するサンプル解析の結果


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


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

nnnnnnnnnn ggggg n

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


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

nnnnnnnnnn ggggg f

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


オブジェクト番号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とする形式です。


しかしながら最近では、これらオブジェクトのリンクや次に利用するフリーなオブジェクトの番号のルールを適用していないPDF文書がほとんどです。


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

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

PDF Easy Parseでトレイラー情報を取得するサンプル解析の結果


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


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


暗号化(Encrypt) ディクショナリ
暗号化 ディクショナリによって、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 Easy Parse Reference)
/Author (Trust Software System)
/Creator (PDF Easy Parse)
/Producer (Trust Software System, PDF Easy Parse)
/CreationDate (D:20140215010203+09'00')
/ModDate (D:20140216040506+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
%lt;< /Filter /FlateDecode /Length 72 >>
stream
... 72バイトのデータ...
endstream
endobj

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


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

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

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


PDF ファイル構造 -概要-」へ <<< >>>「PDF 構造 テキスト」へ


ご質問、お問い合わせ

メールで support@TrustSS.co.jp 宛てにお送りください。
または、質問のページからお送りいただくようお願いします。ご要望も承っております。(匿名で送れます。)




スリーソフト作者の方へ

PDF Easy Parseライブラリを無償で利用できるプログラムがあります。
こちらを参照してください。