PDFファイルの中身:オブジェクト、相互参照表、そして編集しにくい理由
PDFをテキストエディターで開くと、番号付きのオブジェクト、バイト位置の表、圧縮された描画命令が出てきます。1993年のAcrobatからISO 32000-2までの歴史とともに、PDFがWord文書のように直せない理由を説明します。
PDFをメモ帳で開いたことがあれば、1行目に%PDF-1.7のような文字があり、その後に読めない文字がずらりと続くのを見たはずです。その中には、見た目より単純な構造があります。この構造を知ると、「PDFを結合したら2つ目のしおりが消えた」「分割したら合計容量がかえって増えた」「1文字直すだけなのになぜこんなに大変なのか」といった日常の不便がなぜ起きるのかが分かります。
出発点:どのコンピューターでも同じに見える文書
1991年、Adobeの共同創業者ジョン・ワーノックは、のちに「Camelot」メモと呼ばれる社内文書で、機種やOS、ネットワークが違っても文書を同じ見た目でやり取りできる方法が必要だと書きました。当時のAdobeには、すでにレーザープリンター用のページ記述言語PostScriptがありました。ただしPostScriptは完全なプログラミング言語で、10ページ目を描くには基本的に1〜9ページ目までプログラムを実行する必要があり、ファイルの中で繰り返しや分岐、計算もできました。
PDFはPostScriptの描画モデル(線、曲線、文字、画像を座標に置く方式)を受け継ぎつつ、汎用のプログラミング機能を外し、どのページにも直接たどり着けるファイル構造で包み直したものです。AdobeはPDFを1993年6月にAcrobat 1.0とともに出しました。
その後AdobeはPDF 1.0から1.7まで仕様を公開しながら改訂を重ね、2008年にPDF 1.7が国際規格ISO 32000-1になりました。次のPDF 2.0(ISO 32000-2)は、Adobe 1社ではなくISOの委員会で作られた初めての版として2017年に出て、誤りや曖昧さを直した改訂版が2020年に出ています。2023年4月からは、PDF AssociationがAdobe、Apryse、Foxitの支援を受けてISO 32000-2を無償でダウンロードできるようにしています。
ファイルを開くと見える4つの部分
| 部分 | 内容 |
|---|---|
| ヘッダー | %PDF-1.7のようにバージョンを書いた1行目 |
| 本体 | 番号の付いたオブジェクト |
| 相互参照表(xref) | 各オブジェクトがファイルの何バイト目から始まるかの表 |
| トレーラー | 文書の起点(カタログ)が何番のオブジェクトか、xrefがどこにあるか |
本体のオブジェクトはこのような形です。
4 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 595 842]
/Contents 5 0 R /Resources << /Font << /F1 6 0 R >> >> >>
endobj
4 0 objは「4番のオブジェクト(世代番号0)」、<< >>の中は名前と値の組からなる辞書、5 0 Rは「5番のオブジェクトを見よ」という参照です。このページはA4(595×842pt、1ptは1/72インチ)で、描く内容は5番、使うフォントは6番にあると言っています。
文書全体はこうした参照でつながったグラフです。トレーラーがカタログを指し、カタログがページツリー、しおり(Outlines)、フォーム定義(AcroForm)を指し、ページツリーが各ページを、各ページが内容、フォント、画像を指します。
ビューアーはファイルを先頭から読みません。末尾のstartxrefの後にある数値で相互参照表を見つけ、必要なオブジェクトのバイト位置を得てそこへ直接移動します。仕様では相互参照表の各行が正確に20バイトに固定されているので、n番のオブジェクトの行は探さずに計算で求められます。500ページのPDFで300ページ目をすぐ開けるのはこのためです。
PDF 1.5からは、小さなオブジェクトをまとめて1つの圧縮ストリームに入れるオブジェクトストリームと、相互参照表そのものを圧縮した相互参照ストリームが加わりました。最近のPDFをテキストエディターで開いても読めるオブジェクトがほとんどないのは、大半がこうして圧縮されているからです。どれだけ小さくなるかはPDF圧縮率が変わる理由で説明しています。
変更を末尾に追記する増分更新
PDFにはファイル全体を書き直さず、変わった部分だけを末尾に追記する保存方法があります。増分更新(incremental update)です。フォームに名前を書いて保存すると、変更されたフィールドのオブジェクト、そのオブジェクトだけを載せた新しい相互参照セクション、新しいトレーラーがファイル末尾に足されます。新しいトレーラーは前の相互参照表の位置を覚えているので、ビューアーは最新のものから遡って各オブジェクトの最新版を見つけます。
ここから2つのことが起きます。1つは電子署名です。署名は署名した時点までのバイトに対して計算されるため、その後の変更は署名を壊さずに追記でき、しかも「署名後に追加された部分」として見分けられます。もう1つはプライバシーです。増分更新で保存されたファイルでは、消したはずの文字や上書き前の値がファイルの前のほうにそのまま残っていることがあります。見られては困る内容を消したなら、「名前を付けて保存」や最適化でファイルを丸ごと書き直して初めて古い版が消えます。
文字は「文章」ではなく「座標に押したハンコ」
ページの内容ストリームを展開すると、次のような命令が出てきます。
BT
/F1 12 Tf
72 770 Td
(Hello) Tj
ET
「テキスト開始、フォントF1を12ptで、座標(72, 770)へ移動、Helloを表示、テキスト終了」という意味です。ここには段落も改行も、「この行の次にあの行が続く」という情報もありません。ワープロが段落を行に分け、字間を整えた最終結果を、グリフ1つずつ、あるいはひとかたまりずつ位置に固定して記録しているだけです。両端揃えの段落なら、語間の余りまで数値で書かれています。
そのため、PDFで1語直しても後ろの文字は自動で送られません。「東京都」を「東京都千代田区」に変えれば、伸びた分だけ後ろの文字と重なります。エディターが行を組み直そうとしても、まず元の段落がどこで始まりどこで終わるのかを推測しなければなりません。表はさらに厄介で、罫線は別々に描かれた線分で、文字はたまたまその上に置かれているだけです。PDFをWordに変換すると行ごとに改行が入ったり、テキストボックスだらけになったりするのは、変換ソフトがこの推測に失敗した跡です。
日本語の文書では縦書きも加わります。縦組みの文字も結局は座標に置かれたグリフの列なので、抽出ソフトが縦方向の読み順を正しく判断できないと、コピーした文字が横に並んだ順でばらばらになります。
コピーした文字が化けるのも同じ根から来ています。(Hello)の中のバイトは文字コードではなく、埋め込みフォント内のグリフ番号であることがあります。どのグリフがどのUnicode文字かはToUnicodeという別の対応表が教えてくれますが、これがないか間違っていると、画面では正しく見えてもコピーすると化けます。
フォントには「使った文字だけ」が入っている
相手のコンピューターにないフォントでも同じに見せるため、PDFはフォントを内部に持ちます(埋め込み)。和文フォントは数千〜数万字を収めて数MBになることもあるので、ふつうは文書で実際に使った文字だけを抜き出したサブセットを埋め込みます。仕様では、サブセットのフォント名の前に大文字6文字と+を付けると決まっています。PDFのプロパティでABCDEF+MS-Minchoのような名前を見たら、それがサブセットです。
サブセットも編集を難しくする理由の1つです。原本で一度も使われていない漢字を入れようとしても、埋め込まれたフォントにその字の形がありません。エディターは別のフォントで代用するか、パソコンにインストールされた元のフォントを探す必要があり、それもなければその書体では入れられません。
この構造が日常の作業に現れるところ
結合。 結合ツールは2つ目のファイルのページオブジェクトと、そのページが参照するオブジェクトを1つ目のファイルに移し、番号を振り直します。しおりやフォーム定義はページではなくカタログにあるので、ページを移すだけでは付いてきません。PDF結合で一番上のファイルのしおりだけが残るのはこのためです。
分割。 フォントやロゴ画像は一度だけ保存され、複数のページが同じ番号で参照します。文書を10個に分ければ、各ファイルが共有リソースを1つずつ持つ必要があり、合計は原本より大きくなります。PDF分割の結果が思ったより大きいのはこのためです。
圧縮。 文字やベクターはもともと小さく、PDFの容量の大半は画像ストリームと埋め込みフォントが占めます。PDF圧縮で実際に減らせるのも主に画像の解像度と画質です。増分更新で何度も保存して古い版がたまったファイルは、書き直すだけでも小さくなります。
点検。 ファイルが宣言しているバージョン、サブセットとして埋め込まれたフォント、各ページのMediaBoxとCropBoxはPDF情報で確認できます。印刷所から「フォントが埋め込まれていません」と連絡が来たとき、最初に見る場所です。
よくある誤解
- 「PDFは編集できない形式だ。」 違います。増分更新、フォーム、注釈はどれも変更のための仕組みです。ただし変更の単位が「段落」ではなく「オブジェクト」なので、Wordのような編集が難しいのです。
- 「PDFには元の文書が入っている。」 通常は印刷結果だけです。編集用の元データを別に入れるアプリケーションもありますが、PDFの仕様が求めているものではありません。
- 「バージョン番号が高いほど良い。」 ヘッダーのバージョンは、そのファイルが使う機能の上限にすぎません。今も多くのソフトが1.x系で保存しており、PDF 2.0で保存しても画質は上がりません。
- 「トリミングすれば消える。」 ページのトリミングはたいていCropBoxという表示範囲を狭めるだけです。外側の内容はファイルに残っています。
出典
- ISO 32000-1:2008 Document management — Portable document format — Part 1: PDF 1.7(Adobe公開版)
- PDF Association — ISO 32000-2 (PDF 2.0)
- PDF Association — Announcing no-cost access to ISO 32000-2 (PDF 2.0)
- PDF Association — ISO 32000-1
- Adobe Blog — Evolution of the Digital Document: Celebrating Adobe Acrobat's 25th Anniversary (2018)
- Library of Congress — PDF 2.0, ISO 32000-2 (2017, 2020)