PDF-1.7 オブジェクトの種類

[目次へ](https://qiita.com/RT-EGG/items/70f9107c6300f24b23c4)
<b>ver.1.7仕様書 6th edition、3.2に相当します。</b>

#オブジェクトの種類について
PDFでは、以下8種のオブジェクトをサポートします。
- Boolean
- Integer and real number (numeric)
- String
- Names
- Arrays
- Dictionaries
- Stream
- null

オブジェクトには、他のオブジェクトから参照できるよう、ラベル付けされるものがあります。ラベル付けされるオブジェクトをIndirectObject（オブジェクト）と呼びます。

##Boolean Objects
PDFでは、「true」「false」のキーワードで定義されるBooleanオブジェクトをサポートします。
<b>PDFでは大文字、小文字を区別するため、「True」「FALSE」などは意味が異なります。</b>
Booleanオブジェクトは、配列の要素や辞書のエンティティで使われます。また、PostScriptにおける、Booleanを返り値とした関数、比較演算子、条件式にも使われます。（詳しくは仕様書 3.9.4を参照）

##Numeric Objects
PDFのnumericオブジェクトでは、整数と実数を表現できます。
整数オブジェクトは一定範囲の数学的な整数を表します。
実数オブジェクトは近似された数学的な実数を表しますが、固定小数点数で表現されるため、範囲と精度には制限があります。
それぞれの範囲と制限は、PDFを扱うアプリケーションないし実行しているコンピュータでの内部表現に依存します。以下（仕様書 Appendix Cより抜粋）に、典型的な実装の制限を示します。

| Quantity |      Limit      |         Description        |
|:---------|:----------------|:---------------------------|
|Ineger    |$ 2,147,483,647$ |整数最大値は$2^{31}-1$に等しい|
|          |$-2,147,483,648$ |整数最小値は$-2^{31}$に等しい |
|Real      |$±3.403×10^{38}$ |実数の最大/最小値（近似値）    |
|          |$±1.175×10^{-38}$|0ではない、0に最も近い実数値。<br>これに近い値は0とみなされます。|
<b>（仕様書ではRealの0近似値が$10^{38}$となってましたが、多分$10^{-38}$……）</b>

整数は1つ以上の10進数で表現され、+や-の符号が付随することもあります。
（例）123　43445　+17　-98　0
整数オブジェクトが実装上の数値上限を超えた場合は、実数オブジェクトに変換されます。

実数は1つ以上の10進数と小数点、また任意に付随する符号にて表されます。
（例）34.5　-3.62　+123.6　4.　-.002　0.0
実数オブジェクトが実装上の数値上限を超えた場合はエラーとなります。
※ PostScriptでは"16#FFFE"や"6.02E23"といった表記がサポートされますが、PDFではサポートしません。

用法上は実数であっても、整数と透過であれば整数値で記述しても構いません。例えば、1.0は1と記述することも可能です。

##String Objects
stringオブジェクトはバイト値（符号なし1バイト整数）の組み合わせで表現されます。
stringの長さには実装制限が想定されます。なお、この制限はコンテンツ上の文字列にのみ作用します。（以下、仕様書Appendix C）

|         Quantity        | Limit |         Description        |
|:------------------------|:------|:---------------------------|
|String(in content stream)| 32767 |文字列の最大長（バイト）       |

stringオブジェクトには2種類の記法があります。
- ()でリテラル文字を囲う
- <>で16進数を囲う

###リテラル文字列
リテラル文字列は、任意の文字列を（）で囲むことで記述します。リテラル文字列では、対応のない括弧やバックスラッシュは特別扱いされます。
以下は、有効なリテラル文字の例です。
- (This is a string)
- (String may contain newlines
  and such.)
- (String may contain balanced parentheses () and special characters (*!&}^% and so on).)
- (The following is an empty string.)
- ()
- (It has zero (0) length.)

リテラル文字ではバックスラッシュ(\\)をエスケープ文字として扱います。エスケープシーケンスのパターンを以下表に示しますが、これに一致するものがない場合は、バックスラッシュを無視します。

| SEQUENCE |        意味        |
|:---------|:-------------------|
|\\n       | ラインフィード       |
|\\r       | キャリッジリターン   |
|\\t       | タブ                |
|\\b       | バックスペース       |
|\\f       | フォームフィード     |
|\\(       | 左括弧"("           |
|\\)       | 右括弧")"           |
|\\\\      | バックスラッシュ"\\" |
|\\ddd     | 文字コード（8進数）  |

文字列を一行に収めることが難しければ、行末にバックスラッシュを配置することで複数行で記載できます。バックスラッシュに続くEOLマーカーは文字列の一部として捉えるべきではありません。
（例）
(These \\
two strings \\
are the same.)
(These two strings are the same.)

8進数文字コードでは、ASCII文字で表現できない文字を表します。
（例） (This string contains \245two octal characters\307.)
"\ddd"のdddは、1~3文字の8進数文字で、4文字目以降は無視されます。このエスケープシーケンスの後に数値文字が続く場合、0埋めで3文字にすることで対応できます。例えば、
（\\0053）
は、8進数で005（^E）の後に文字の3が続くことになります。
(\\053) (\\53)
は共に同じ値であり、8進数で53(+符号)を意味します。
これにより、ASCII文字のみを利用して、7ビットASCII文字の範囲外の文字を表現できます。

###16進数文字列
文字列は16進数表記されることがあります。これは、文書にバイナリデータを含む場合に適しています。
16進数文字列は、2文字1組以上の16進数文字の並びを< >で囲むことで表現します。
（例）<4E6F762073686D6F7A206B6120706F702E>
white-space文字が含まれる場合は無視します。
文字が欠けている場合（文字数が奇数の場合）には、末尾に0を足して補完します。例えば、
<901FA> は <901FA0> と認識します。

##Name Objects
Nameオブジェクトは文字の並びによって定義されます。
Nameオブジェクトは"/"で開始し、"/"自体はNameオブジェクトに含みません。Nameオブジェクトはregular文字で構成され、delimitterやwhite-spaceは含まれません。"/"の直後にwhite-space文字があってはいけません。また、大文字/小文字を区別するので、/Aと/aは異なるNameオブジェクトです。
（有効なNameオブジェクト例）
- /Name
- /ASomewhatLongerName
- /A;Name_WithVarious***Characters?
- /1.2
- /$$

PDF1.2以降では、ヌル文字以外のすべての文字を、#の後に2桁の16進数文字を記述することで表現できます。これは、delimitterやwhite-space文字を表現するのに有用です。
（例）

|     ファイル上の表記      |    識別される文字列   |
|:------------------------|:--------------------|
|/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                  |
\#の扱いは、PDFのバージョンによって注意が必要です。
- PDF1.1では、#は名前の一部として利用可能でした。そのため、/A#BはそのままA#Bと認識されるべきです。
- Acrobat Distillerは必要に応じてPostScriptを出力し、これには#が含まれることがあります。
- Acrobat4.0以前では、Nameオブジェクトは個々のプラットフォーム依存（OSやローカライズ）のエンコード（Shift-JISやBigFiveなど）でテキストが解釈されます。この場合と、通常のUTF-8エンコーディングとを見極める必要があります。UTF-8でない場合は、代わりにプラットフォームに応じたエンコーディングに従って解釈できます。

Nameオブジェクトの最大長には実装制限は127文字です。なお、16進数表記を含む場合は、16進数表記としての文字数ではなく、変換後の文字列で換算します。例えば、"/A#20B"は6文字ではなく3文字になります。

##Array Objects
Arrayオブジェクトは、一次元のオブジェクトの配列です。複数種類のオブジェクトを格納することができ、Arrayオブジェクトもまた例外ではありません。PDF仕様としては一次元配列のみをサポートしますが、Arrayオブジェクトのネストを作ることで高次元の配列を再現することができます。
Arrayオブジェクトは、[ ]で1つ以上のオブジェクトを囲むことで表されます。
（例） [549　3.14　false　(Ralph)　/SomeName]

##Dictionary Objects
Dictionaryオブジェクトは、2つ1組のオブジェクトのペア（エントリ）のテーブルです。1つ目の要素をkey、2つ目の要素をvalueと呼びます。
keyはNameオブジェクトでなければいけません。valueは、Dictionaryオブジェクトを含め、任意種類のオブジェクトが許容されます。valueがnullオブジェクトであるエントリは無視されます。エントリの最大数には実装制限があります（Appendix C にあるとのことですが、見つかりませんでした……）。
※ 1つのDictionaryオブジェクトに、同じkeyを持つエントリが複数あるべきではありません。この場合のエントリのvalueの動作は未定義です。

Dictionaryオブジェクトは、エントリを << >>で囲むことで記述します。

```
（例）
<< /Type /Example
   /Subtype /DictionaryExample
   /Version 0.01
   /IntegerItem 12
   /StringItem (a string)
   /SubDictionary << /Item1 0.4
                     /Item2 true
                     /LastItem (not!)
                     /VeryLastItem (OK)
                  >>
>>
```

##Stream Objects
StreamオブジェクトはStringオブジェクトと同様にバイト列で記述されますが、Stringオブジェクトのように最大長の制限が設けられていません。そのため、画像などの大きなデータはStreamオブジェクトで提供されます。
Streamオブジェクトは、Dictionaryオブジェクトの後に、"stream"と"endstream"で囲むことで記述します。

```
（例）
<<
 ...
>>
stream
...Zero or more bytes...
endstream
```
SteramオブジェクトはIndirectObjectでなければいけません。また、先行するDictionaryオブジェクトはIndirectObjectであってはいけません。
"stream"キーワードは、先行するDictionaryオブジェクトの終了位置より改行してから記述しなければなりません。このときの改行コードはCR単体であってはいけません。
PDF1.2以降では、Streamオブジェクトのデータを外部ファイルに依存することができます。このとき、"stream"から"endstream"にあるデータは無視します。

次に、先行するDictionary部が持つ、Streamデータを補足するエントリの説明をします。

- Length
　値はintegerで、必須のエントリです。
　Streamオブジェクトを構成するバイト列は"stream"と"endstream"の間にありますが、その長さは"Length"エントリにて指定されます。なお、この長さには、"endstream"自体は含みません。"endstream"の前には改行が推奨されます。指定されたデータ量より実際のデータが多い場合にはエラーになりますが、"endstream"の前に改行コードが含まれることはあります。また、データがエンコードされている場合、指定される長さはエンコードされた結果の長さとなります。　

- Filter
　値はNameオブジェクトのArrayオブジェクトで、必須ではありません。
　Streamデータに適用されるフィルタの名称です。フィルタが複数設定される場合、設定される順序で記述する必要があります。

- DecodeParam
　値はArrayオブジェクトまたはDictionaryオブジェクトで、必須ではありません。Filterで指定されるフィルタがデフォルトでないパラメータを持つ場合は必須となります。全てのフィルタがパラメータを必要としない、またはデフォルトパラメータを持つ場合は、DecodeParamは省略できます。
　Arrayオブジェクトで表される場合、パラメータを必要としないフィルタに対しては、nullを指定します。
なお、Acrobatのビューワでは、DPをDecodeParamsの省略形として認識します。DPとDecodeParamの両方がエントリにある場合は、DecodeParamを優先します。

- F
　PDF1.2以降で有効です。必須ではありません。
　Streamの実データを持つ、外部ファイルを意味します。Fエントリを持つ場合、"stream"から"endstream"の間のデータは無視します。フィルタは"Filter"ではなく"FFilter"により、フィルタに対するパラメータは"DecodeParam"ではなく"FDecodeParam"にて指定されます。"Length"は通常通りデータバイト数を示しますが、通常は0です。
　Acrobat3.0以上での挙動について、Appendix H-46を参照してください。<b>（ここでは省略）</b>

- FFilter
　PDF1.2以降で有効です。値はNameオブジェクトのArrayオブジェクトで、必須ではありません。
　Fエントリで指定されるファイルのフィルターを示します。適用ルールはFilterエントリと同じです。

- FDecodeParam
　PDF1.2以降で有効です。値はArrayオブジェクトまたはDictionaryオブジェクトで、必須ではありません。
　FFilterに対して適用される以外、適用ルールはDecodeParamエントリと同じです。

- DL
　PDF1.5以降で有効です。値はInteger（Numeric）オブジェクトで、必須ではありません。
　Lengthがエンコードされたデータ量を示すのに対し、こちらはデコードされた結果のデータ量を示します。これは、デコード前に、ディスクに十分な空き容量があるかを確認するために有用です。
　この値はあくまで補足として捉えるべきであり、一部のフィルタではこの値が正確にならない可能性があります。

##Null Objects
Nullオブジェクトは、ただNullのみを意味するオブジェクトです。"null"で記述されます。
例えばIndirectObject（後述）について、参照先のオブジェクトが存在しない場合にはNullオブジェクトを指定します。
例えばDictionaryObjectについて、ValueがNullであるエントリは省略されます。

##Indirect Object
PDF内のオブジェクトは、IndirectObjectとしてラベルで管理されることがあります。
ラベルは、以下の2つから
- object number: 整数値。ファイル内で降順となるのが一般的だが、必要条件ではない。
- generation number: 0以上の整数。新規に作成されるオブジェクトに対しては0であり、ファイルの更新に応じてインクリメントが発生することがある。
IndirectObjectの定義は、object numberとgeneration numberでラベル宣言を行い、続く"obj"と"endobj"で囲まれる範囲で行われます。

```
（例）object number=12、generation number=0　のIndirectObject
12 0 obj
    (Brilling)
endobj
```
定義されたオブジェクトは、ラベルと"R"キーワードで参照できます。

```
（例）
12 0 R
```

未定義のIndirectObjectへの参照があった場合は、エラーとはせず、参照先をNullオブジェクトとします。

次の例では、StreamObjectのLengthエントリについて、IndirectObjectへ参照することで定義しています。このように、定義がファイル上の後に来ることも許容されます。

```
（例）
7 0 obj
    << /Length 8 0 R >>
stream
    BT
        /F1 12 Tf
        72 712 Td
        (A stream with an indirect length) Tj
    ET
endstream
endobj

8 0 obj
    77    %The length of the preceding stream
endobj
```