PDFってこうなってる? Part 5: テキストエディタでHello World PDFを自作する
PDFの内部構造を理解するために、テキストエディタだけで「Hello World」を表示するPDFファイルを一から自作します。ストリームオブジェクトやテキスト命令を詳しく解説します。

PDFファイルは一見するとバイナリデータの塊のように思えますが、実はその基本構造はテキストエディタでも読み書きできるほどシンプルです。本シリーズのPart 1:PDFを理解するための第一歩では、PDFファイルを構成するさまざまなオブジェクトについて説明しました。Part 5となる本記事では、Part 1で紹介したストリームオブジェクトに焦点を当て、テキストエディタだけで「Hello World」を表示する最小限のPDFファイルを一から組み立てます。
ストリームオブジェクトの役割
PDFファイルの中で、実際にページの見た目(テキスト、図形、画像の配置など)を記述しているのがストリームオブジェクトです。テキストエディタでPDFファイルを開くと、多くの場合、ファイルの大部分がストリームオブジェクトで占められていることがわかります。
ストリームオブジェクトには、ページ上に何をどのように描画するかという「命令」が格納されています。テキストの表示位置、フォントの指定、図形の座標、線の太さ、色の指定など、ページのレンダリングに必要な情報がすべてストリームの中に記述されます。
ストリームの基本構造
ストリームオブジェクトは他のPDFオブジェクトとは異なる書式を持ちます。まずディクショナリー(辞書)部分から始まり、その後にstreamキーワードで囲まれた実データが続きます。
10 0 obj
<< /Length 45 >>
stream
...圧縮された内容...
endstream
endobjディクショナリーには必ず /Length エントリが含まれている必要があり、これはストリームデータのバイト数を示します。PDFビューアはこの値を参照して、ストリームデータの範囲を正確に把握します。/Lengthの値が実際のバイト数と一致しない場合、PDFビューアがファイルを正しく表示できなくなるため注意が必要です。
実際のPDFファイルでは、ストリームデータは通常FlateDecodeなどのフィルタで圧縮されています。圧縮されている場合はディクショナリーに /Filter エントリが追加されます。しかし本記事で作成するHello World PDFでは、わかりやすさを優先して圧縮なしのプレーンテキストでストリームを記述します。
テキスト描画命令の構文
ストリーム内でテキストを描画するには、専用のオペレーター(命令)を使用します。以下は「Hello World!」を画面に表示するための最小限の命令です。
BT /F1 24 Tf 175 720 Td (Hello World!) Tj ET一見すると暗号のようですが、各要素には明確な意味があります。
| オペレーター | 正式名称 | 意味 |
|---|---|---|
| BT | Begin Text | テキスト描画の開始を宣言する |
| Tf | Set Text Font | フォントとサイズを指定する(/F1フォント、24ポイント) |
| Td | Move Text Position | テキストの表示位置を指定する(左から175単位、下から720単位) |
| Tj | Show Text | 括弧内のテキストを描画する |
| ET | End Text | テキスト描画の終了を宣言する |
この命令で、ページの座標(175, 720)の位置に、/F1フォント・24ポイントサイズで「Hello World!」というテキストが描画されます。PDFの座標系は左下が原点(0, 0)です。このPDFのページサイズは500 x 800ポイントなので、720という値はページの上部付近を意味します。
リソース辞書とフォント参照
ストリーム内で使用した /F1 は、フォントの「参照名」です。この名前が実際にどのフォントを指すかは、ページのリソース辞書(Resource Dictionary)で定義します。
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 500 800]
/Contents 6 0 R /Resources 4 0 R >>
endobj
4 0 obj
<< /Font << /F1 5 0 R >> >>
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobjここでは3つのオブジェクトが連携しています。
- オブジェクト3(ページオブジェクト): ページのサイズ(MediaBox)、コンテンツ(Contents)、リソース(Resources)を定義します
- オブジェクト4(リソース辞書):
/F1という名前をオブジェクト5に紐付けます - オブジェクト5(フォントオブジェクト):
/F1の実体がHelveticaフォント(Type1形式)であることを定義します
この間接参照の仕組みにより、同じフォントを複数のページで使い回す場合でも、フォント定義は1か所で済みます。これはPDFビューアの読み込み効率を高めるための設計です。
完全なHello World PDFの全体構造
以下が、テキストエディタで作成できる完全なHello World PDFの全文です。これをテキストエディタに貼り付けて .pdf 拡張子で保存すれば、PDFビューアで開くことができます。
%PDF-2.0
1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj
2 0 obj
<< /Type /Pages /Kids [3 0 R] /Count 1 >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 500 800]
/Contents 6 0 R /Resources 4 0 R >>
endobj
4 0 obj
<< /Font << /F1 5 0 R >> >>
endobj
5 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj
6 0 obj
<< /Length 44 >>
stream
BT /F1 24 Tf 175 720 Td (Hello World!) Tj ET
endstream
endobj
xref
0 7
0000000000 65535 f
0000000009 00000 n
0000000056 00000 n
0000000111 00000 n
0000000212 00000 n
0000000250 00000 n
0000000317 00000 n
trailer
<< /Size 7 /Root 1 0 R >>
startxref
406
%%EOF各部分の役割
このPDFは、以下の構造で構成されています。
- ヘッダー (
%PDF-2.0): PDFのバージョンを示します - カタログオブジェクト (オブジェクト1): PDFのルートオブジェクトで、ページツリーへの参照を持ちます
- ページツリー (オブジェクト2): 全ページを管理するオブジェクトで、子ページの配列と総ページ数を持ちます
- ページオブジェクト (オブジェクト3): 個々のページの定義で、サイズ・コンテンツ・リソースを参照します
- リソース辞書 (オブジェクト4): ページで使用するフォントなどのリソースを定義します
- フォントオブジェクト (オブジェクト5): 使用するフォントの詳細情報を定義します
- コンテンツストリーム (オブジェクト6): 実際の描画命令を格納します
- 相互参照テーブル (xref): 各オブジェクトのファイル内オフセット位置を記録します
- トレーラー (trailer): 相互参照テーブルの位置とルートオブジェクトを指定します
実際に試す際の注意点
テキストエディタでこのPDFを作成する際は、以下の点にご注意ください。
- 文字コードはASCIIまたはUTF-8(BOMなし)で保存してください
- 改行コードの違い(CR、LF、CR+LF)により、/Lengthの値やxrefのオフセット値がずれる場合があります。正しく表示されない場合は、これらの数値を調整してください
- 一部のPDFビューアは厳密なバリデーションを行うため、オフセット値が正確でないとエラーになることがあります
次のステップ
本シリーズはPart 6:パスで図形を描こうへ続きます。Part 6ではグラフィックコマンド(パス描画命令)を使用して、PDFに直線、四角形、曲線などの図形を追加する方法を扱います。テキストだけでなく、図形描画の命令もストリームオブジェクトの中に記述される仕組みを理解することで、PDFの内部構造への理解がさらに深まるでしょう。
PDFアプリ開発ツール(SDK)をお探しのみなさま、効率のよい開発作業のためにJPedal、BuildVu、JDeliがきっとお役に立つことと思います。これら3製品は無料で試用していただけますので、まずはお試しのうえ、ぜひ導入をご検討ください。

開発者向けPDF入門ガイド
PDFの仕様や活用方法など、開発者に必要な情報をコンパクトにまとめました。初めてPDFを扱う開発者にも分かりやすく、基礎から応用までカバーしているため、PDFのポテンシャルを最大限に引き出し、アプリケーション開発やドキュメント管理の効率化を図るための手引きとなるでしょう。