PDF 内部構造 構造の概念 簡単な説明

提供:yonewiki

PDF 内部構造に戻る。

概要

 ファイルの構造の大まかな分類があるので、その分類をここで説明します。PDF内部構造の用語にもなれていかないといけません。この記事では最初の一歩に必要な内容を記述したいと思います。


PDFファイルのテキストが一つあるだけのシンプルな構造のファイルイメージは以下のようになります。

%PDF-1.7
%★(適当な129~255までの値を何バイトか)
1 0 obj 
<< /Type /Pages
   /Count 1
   /Kids [2 0 R] 
>>
endobj 
2 0 obj 
<< /Type /Page
   /MediaBox [0 0 ★(xx xx 横 縦 用紙サイズpixel)]
   /Resources 3 0 R
   /Parent 1 0 R
   /Contents [4 0 R]
>>
endobj 
3 0 obj 
<< /Font 
     << /FBase 
          << /Type /Font
             /BaseFont /Helvetica-Bold
             /Subtype /Type1 >>
     >>
>>
endobj 
4 0 obj 
<<
/length ★(xx stream部(30行目~36行目終わり)のバイト長)
>>
stream
1. 0. 0. 1. ★(xx. xx 描画座標位置 左下原点で上と右方向に増えていくpixel座標値). cm
BT
  /FBase 12. Tf
  (PDF Strings! Parts) Tj
ET 
endstream 
endobj 
5 0 obj 
<< /Type /Catalog
   /Pages 1 0 R
>>
endobj xref
0 6
0000000000 65535 f 
0000000★(xxx 1 0 objの始まるバイト長) 00000 n 
0000000★(xxx 2 0 objの始まるバイト長) 00000 n 
0000000★(xxx 3 0 objの始まるバイト長) 00000 n 
0000000★(xxx 4 0 objの始まるバイト長) 00000 n 
0000000★(xxx 5 0 objの始まるバイト長) 00000 n 
trailer
<< /Size 6
   /Root 5 0 R
>>
startxref
★(xx ファイルサイズ バイト長)
%%EOF

 サンプルソース:PDF_String_Sample-text.pdf‎
 サンプルPDF :PDF_String_Sample.pdf‎


 サンプルソースを載せましたが、これもpdfとして開けば、Acrobat Readerが気を利かせて、PDF文書として表示されますが、2つのファイルリンクを右クリックしてリンクをファイルとして保存のようにしてダウンロードしたものをテキストエディタで開くと、肝心なところが自動補完されたっぽいことがわかります。PDF_String_Sample.pdf‎には★マークの部分の数値がすべて埋まっています。


 ちなみにPDFtkのコマンドは以下の通りになります。

PDFtk PDF_String_Sample-text.pdf output PDF_String_Sample.pdf


 ファイルの中身について、はじめて見たときは、なんじゃコレ。って感じでした。皆さんの中にも初めての人がいたら同じような気持ちだったはずです。冷静にみてみると見えてくるものがあります。最初の2行あたりは、すべての拡張子のファイルにもあるファイルヘッダ部です。なんらかのファイル操作をしたことがある人なら知っているかもしれません。★マークがあるところは、任意の数値を指定したり、PDFtkに自動で算出してもらう数値だったりが入る箇所です。このファイルは実際はバイナリファイルですが、テキストで閲覧しても上記のように表示されるくらいテキストに近いものです。そして出回っているPDF生成ツールを使うとたいていは圧縮されて、なにがなんだかわからないファイルになっているのですが、上記のようにテキストでも理解できる非圧縮の見通しのいいPDFファイルも存在しています。ファイルを理解したい人にとってはこれでいいのですが、世の中そうもいかないらしい。いまファイルを理解しようとしている我々も含めて、単純に便利に使いたい人の方が多い。では上から見てみます。


 %PDF-1.7


 ふむふむ。PDF-1.0 ~ PDF-1.7 までのバージョンがありますので、それぞれの仕様にあわせた値なので数字の部分は変わります。大した機能を使わない文書ならPDF-1.1とかを指定しても問題ないでしょう。むしろ大きなバージョンは複雑な仕様になっているので、きちんとすべての情報を書けていなくて動かなくなることがあるかもしれません。自分ごときが扱うときは、まだ1.1くらいしか使ったことないです。1.1でも普段使う機能は出来上がってます。ちなみに1.1の仕様に沿っていれば現状の1.7に対応しているリーダーでは開けるように、後方互換が完全に保証されています。逆に1.7の文書も1.1でひらける前方互換も概ね(おおむね)保証されているようです。ヘッダのあとにファイルがバイナリファイルであることを明示する工夫として、128以上のASCII文字列(ASCII文字コードは0~127の値とアルファベット文字を主に数値と文字を結び付けた対応関係があります。詳しくはASCII文字コードで調べて下さい)の外側の数値を記載しています。


 そうすると3行目から現れる


 1 0 obj


 のような表現が、2 0 obj、3 0 obj …のように飛び飛びで現れていて、それぞれはendobjというキーワードで対になっています。


 1 0 obj
 …
 endobj


 これがオブジェクトという単位です。まだオブジェクトの中身はわからなくていいです。まずは全体を見渡しましょう。数字は先頭からオブジェクト番号世代番号と呼ばれています。オブジェクト番号はファイル内で唯一の番号(ユニークな番号)になっている必要があります。連番である必要がありそうです。最後のendobjのある42行目からはx x obj ~ endobjという対がおわり


 endobj xref
 0 6
 …
 startxref


 のような構造があります。この部分は相互参照テーブルと呼ばれています。オブジェクトは文書の中身を記述して構成していく要素ですが、相互参照テーブルは、そのオブジェクトがどこにあるかを記述したりします。実はファイルを開いたときは、たいていの閲覧ソフトは、この部分を探します。いまから見たいページがどこにあるかが記録されているからです。オブジェクトはフォルダのようなツリー構造になっていて、それぞれのオブジェクト内で、何がぶら下がっているか、どこにぶら下がっているかという情報をもっています。相互参照テーブルはその頂点であるルートのオブジェクトがどれかを保持したり、オブジェクトがいくつあるかという情報も保持しています。


 そして、最後に55行目で相互参照テーブルの開始位置をバイト単位で指定した数値部分があって、ここでは、0 を指定しています。0と記述しておけば、PDFtkが相互参照テーブルの開始位置のバイト値を補完してくれます。最終行は%%EOFというファイル終端記号で終わっています。


 PDFファイルとは、こういう構造になっています。ここまでの説明では、まだ理解しきれるものではありませんが、シンプルな表現のみの文書の全貌はみえてきたと思います。


 5つの obj がどのような役割なのかを確認します。ちなみに<< … >>のような二重の小なり、大なり記号は、辞書という意味があり、いくつかの情報をまとめて、無意味順序として記述するという意味があります。単なる塊とも取れます。でも塊の中に指定されているものを、そのオブジェクトや名前が差している内容とみなすので、辞書の指定はよく使います。


 ■5 0 obj

 ルートオブジェクト(カタログ:目録 全体の目次といってもよいかも)です。相互参照テーブルのトレーラ部で/Root 5 0 R のように指定されています。5 0 R は/Rootという名前のモノは5 0 objを参照(Referrence)しますという意味の 5 0 Rです。x x R という形式はよく登場します。/Root という表記もよく登場します。 / のあとに文字列が記述されたようなパターンを名前といい。名前には固有の役割があるものはキーと呼んでいて、ユーザが自由につけるものは名前と呼んでいます。プログラムで言うところの変数みたいなものです。


 5 0 obj には/Type は /Catalogだと指定しています。カタログには参照するページとして/Page 0 1 R がありますと指定もしています。0 1 obj は カタログのページ構成要素なんですね。


 ■1 0 obj

 ページです。5 0 obj のカタログにぶら下がっているページ要素という意味です。


 5 0 obj には/Type は /Pageだと指定しています。/Count は 1 と指定してあるので、このページは1つのページのオブジェクトであるということになります。このページの詳細情報をこの1 0 objには書かずそのページ要素の詳細は/Kidsという名前の参照先に書くことにしていて、/Kids [2 0 R] なので、2 0 R を参照しています。通常はフォントの設定や用紙の設定を個別にオブジェクトとして記述するので、このように、1つのページの情報はページの親的なオブジェクトから、参照して、また参照してというツリー構造になります。

 ■2 0 obj

 このオブジェクトもページです。1 0 obj のページにぶら下がっているページの要素です。


 5 0 obj にも/Type は /Pageだと指定しています。但し、要素には1 0 obj には記述しなかったような名前について定義されています。/MediaBox は 用紙サイズをピクセル単位で指定します。A4用紙サイズの縦なら[0 0 1033 1462]というように指定します。[ ] 角カッコ(ブラケット)は配列の中身を空白区切りで記述するような仕組みになっています。このような記述方法を配列と呼んでいます。プログラムの配列は角カッコを使って要素数を指定しますが、そのような要素数の指定をするといったことの意味はありません。プログラムでいうと { } 波カッコ(ブレース)のような配列初期化指定に似ているかもしれません。
 ページ要素の親は 1 0 obj という意味で/Parent 1 0 R が指定されています。


 このページの資源(Resourceの直訳は資源とはいうものの、日本語としては、ページの書式ですね。英語ではこういったものもResourcesと言うのでしょう。)は3 0 obj を参照するようにという意味で/Resources 3 0 Rが指定されています。


 ページの内容(コンテンツ)は /Contents [4 0 R]という具合に配列で 4 0 R にあると指定しています。このように参照値を入れる場合の配列は参照値を示すための空白(4 0 R)と配列の区分けの空白が混ざりますが、PDFの書式としてはなんら問題にならないようです。


  ■3 0 obj

 このオブジェクトには書式を指定する辞書が指定されています。この辞書の中で/Fontという名前の値を指定することで、書体を指定しています。/Font には一つの辞書が結び付けられています。その辞書は /FBase というユーザ指定の名前をもっていて、/FBase にはまた辞書の値が指定されています。そこに、/Type は /Font 、/BaseFont は /Helevetica-Bold、/Subtype は /Type1 であると指定しています。


 ややこしい感じで設定されていますが、/FBaseというユーザ定義のフォント書式が定義されている上でフォントの設定を実際に3つ指定しているという形式です。/BaseFontで実際にフォント名をしていして、使うフォントを定義しています。英字フォントはフォント名にハイフン「-」で連結させるようにしてBold(太字)やItalic(斜体)を使うという指定ができるものが多いです。フォント名には英字フォント名というのがあるので、その値を設定します。/Subtypeもややこしいですが、フォントにはいくつかの形式があります。標準Type1(ASN Developer ProgramサイトからもダウンロードできるAdobeFontMetricsFileFormatファイル)は以下のとおりらしいです。Obliqueは斜体です。Italicと同様の意味です。

   Courier, Courier-Bold, Courier-Oblique, Courier-BoldOblique
   Helvetica, Helvetica-Bold, Helvetica-Oblique, Helvetica-BoldOblique
   Times-Roman, Times-Bold, Times-Italic, Times-BoldOblique
   Symbol, ZapfDingbats


 他にも/SubTypeには、Type0, MMType1, Type3, TrueType, CIDFontType0, CIDFontType2というのがあります。そのあたりはまた別途です。日本語フォントなんかを使う我々はもう少し、深く勉強しないと、PDF文書を扱えるレベルには到達できないようになっています。


  ■4 0 obj

 ここにコンテンツを置きます。stream部をもうけるので、名前/Lengthの値にstreamのバイト長をちゃんと数えて埋める必要がありますが、PDFtkによって自動で算出するので、変換前のテキストPDFには << >> のように記述して、辞書がここにはいるよ。よろしく。という感じだけ書いておけば良いです。


 streamからendstreamの間でテキストを描くペンを移動させるため 1. 0. 0. 1. 50. 50. cm のようにします。この表記はもっと意味深いのですが、1(X方向の倍率), 0, 0, 1(Y方向の倍率), 50(X方向移動), 50(Y方向の移動)を意味しています。このときの cm をオペレータ、1, 0, 0, 1, 50 , 50 はオペランドといいます。これについても、のちほど触れたいと思いますが、cm オペレーターは単純に移動をするためのものではなく、空間座標変換というような簡単にはわかりにくい機能をもっています。ここでは、cm オペレータはそういう機能があるんだなっていうことを把握しておいてもらえればいいと思います。


 BT~ETがテキストの始まりと終わりを示すオペレータです。Tf はテキストサイズを設定するオペレータです。第二オペランドにポイント(72分の1インチが1ポイント)という単位のテキストサイズの大きさ値を設定します。第一オペランドにはテキストフォント書式を設定したテキスト名前(こういうのをフォントリソースの名前と呼びます)を設定します。ユーザが好きな名前を付けていいものに、ある一定の役割があるものを関連付けてある必要があるというパターンはよくあります。Tj は第一オペランドで設定した文字列を出力するということです。

 

関連記事

フォント TrueType 構造解析

 

PDF 内部構造に戻る。