PDF手書き

PDFファイルはバイナリ形式と言われているが,ラスタ画像とか圧縮機能を使わなければ一応テキストエディタだけでvalidなものを書ける.しかし間接参照のためのバイト・オフセット値とかを色々矛盾なく書き込まなければならないので,その辺を自動で処理するツールをC++で書いてみた.Adobe Readerが文句を言わず読み込んでくれるから合ってるんだろう.

しかしひどく込み入った仕様だ... 次はU3D形式にトライするつもりなんだが,そっちはさらに上を行くようだ*1.こういうのこそ,Bidirectional programming*2で処理すべきなのかな? Bidirectional programmingなら論理学的に対応の保障されたexport/inportルーチンが同時にできる(片方のみを組む作業は楽にはならないけど)って言うんだよね?

こういうのが,

<< /Type/Catalog
   /Pages ((Pages)) >>

<< /Title(Test PDF file 02)
   /Author(NODA Kai)
   /CreationDate >>

((Pages))
<< /Type/Pages
   /Count 1
   /Kids[((Page 1))]
   /MediaBox[0 0 595 842] >>

((Page 1))
<< /Type/Page
   /Parent ((Pages))
   /Resources << /Font << /F1 ((Font 1)) >> >>
   /Contents ((The Contents)) >>

((Font 1))
<< /Type/Font
   /Subtype/Type1
   /BaseFont/Times-Roman >>

((The Contents))
<< /Length >>
stream
BT
/F1 12 Tf
200 750 Td
(Hello, world!) Tj
ET
endstream

こうなる:

%PDF-1.5
%μμμμ
1 0 obj
<< /Type/Catalog
   /Pages 3 0 R >>
endobj
2 0 obj
<< /Title(Test PDF file 02)
   /Author(NODA Kai)
   /CreationDate(D:20080609073341+09'00') >>
endobj
3 0 obj
<< /Type/Pages
   /Count 1
   /Kids[4 0 R]
   /MediaBox[0 0 595 842] >>
endobj
4 0 obj
<< /Type/Page
   /Parent 3 0 R
   /Resources << /Font << /F1 5 0 R >> >>
   /Contents 6 0 R >>
endobj
5 0 obj
<< /Type/Font
   /Subtype/Type1
   /BaseFont/Times-Roman >>
endobj
6 0 obj
<< /Length 46 >>
stream
BT
/F1 12 Tf
200 750 Td
(Hello, world!) Tj
ET
endstream
endobj
xref
0 7
0000000000 65535 f^M
0000000015 00000 n^M
0000000066 00000 n^M
0000000175 00000 n^M
0000000262 00000 n^M
0000000372 00000 n^M
0000000447 00000 n^M
trailer
<< /Size 7
   /Root 1 0 R
   /Info 2 0 R >>
startxref
542
%%EOF

^Mのところだけは改行がCR+LFになっている(エディタで書くときは全部の改行をCR+LFにすればよい)."μ"(と言うか0xb5) の並んだ行は,別にいらないんだけど,「あえてASCIIの範囲外の文字を先頭近くに入れておくことでバイナリ・ファイルであることを主張するのが良い」とされているので付けてみた.
実際のファイル: