ByteScope

PDF ファイル形式

Portable Document Format。Adobe による固定レイアウトの文書標準。

MIME タイプ
application/pdf
拡張子
.pdf
カテゴリ
ドキュメント

マジックナンバー(ファイル署名)

0x00000000255044462D%PDF-'%PDF-' + version

PDF 形式について

PDF の中身は番号の付いたオブジェクト(辞書、配列、ストリーム、数値、文字列)のグラフと、各オブジェクト番号をファイル内のバイトオフセットに対応づける相互参照テーブルです。500 ページの PDF がビューアで一瞬に開くのはこの設計のおかげで、末尾の数百バイトを読んで startxref から相互参照テーブルへ飛び、必要なオブジェクトだけを直接取りに行きます。同時に、PDF が追記にはやたら強く、バイト位置がずれる編集にはやたら弱い理由でもあります。テーブルに入っているオフセットはすべて絶対値だからです。

ヘッダーの構造(バイト単位)

オフセット長さフィールド意味
05%PDF- header markerASCII 5 バイトの 25 50 44 46 2D。PDF は最上位のレベルではテキストに近い形式なので、これは文字どおり PostScript 流のコメント行です。パーセント記号がコメント文字であり、PDF を知らないパーサーにとっても 1 行目は合法なテキストになります。
53Version numberISO 32000-1 とその前身の Adobe 版なら '1.0' から '1.7'、ISO 32000-2 なら '2.0'。ただしここのバージョンは事実ではなく下限です。文書カタログの /Version キーが上書きして引き上げられるので、1.4 と書かれたファイルが 1.7 の機能を使っていても違反ではありません。
81Header end-of-lineLF 単体(0A)、CR 単体(0D)、または CR LF の組。組の場合はここが 2 バイトになり、以降がすべて 1 バイトずれます。ヘッダ行にこれ以外のものを置くことは許されていません。
9variableBinary comment lineISO 32000-1 の 7.5.2 は、バイナリデータを含むファイルではヘッダの次にコメント行を置き、そこに符号が 128 以上のバイトを 4 つ以上入れることを推奨しています。目的はただ 1 つ、転送ソフトにテキストではなくバイナリだと判断させることです。よくある生成器は %âãÏÓ を書きます。無くても違反ではありませんが、書き手が雑だったことは分かります。
-55%%EOF marker整形式のファイルの最終行は 5 バイトの 25 25 45 4F 46 です。後ろに改行が付くこともあるので、読む側は固定位置を信じずに末尾 1024 バイトを後ろ向きに走査します。なお %%EOF が複数あるファイルは壊れているのではなく、増分更新されただけです。
variablevariablestartxref and the trailer%%EOF の直前に 'startxref' というキーワードが来て、次の行に 10 進のバイトオフセットが入ります。読む側はそこへ飛んで相互参照テーブル(または相互参照ストリーム)を見つけ、そこ経由で /Root、/Info、/Encrypt にたどり着きます。ここまでの何一つ固定位置にはなく、だからこそ末尾のマーカーは走査して探すしかないのです。

似た形式との見分け方

紛らわしい形式見分け方
PDF/APDF/A は長期保存用、PDF/X は印刷入稿用のプロファイルで、どちらもオフセット 0 には痕跡を残しません。準拠レベルは署名ではなくメタデータだからです。PDF/A のファイルは XMP メタデータストリームの中で pdfaid 名前空間を使って part と conformance level を宣言し、さらに全フォントの埋め込みと output intent が必須です。つまり XMP で PDF/A を名乗っていても検証に落ちることはあり得ますし、ヘッダはどちらとも教えてくれません。
Encrypted PDFこれも先頭バイトは同じ。手がかりはファイル末尾の trailer 辞書にある /Encrypt キーです。実務上 PDF の暗号化がたいてい何を意味するかは知っておく価値があります。ユーザーパスワードが空でオーナーパスワードだけの権限制御であることが多く、その場合、中身は完全に読めていて、印刷やコピーの制限はビューアが行儀よく従っているだけです。ストリームまで暗号化するユーザーパスワードとは別物です。
OLE2 / CFB「文書を送って」と言われたときに出てくる 2 つの選択肢です。2007 年より前の Word ファイルは D0 CF 11 E0 で始まる Compound File Binary コンテナ、PDF は %PDF-。後工程で効く違いは、PDF がページ上のグリフ位置を固定するのに対し .doc は固定しないこと。フォントが無いマシンで .doc がレイアウト崩れを起こし、PDF は崩れないのはそのためです。
PostScriptPDF の直系の祖先で、オブジェクト構文もコメント文字も同じなので今も混同されます。PostScript ファイルは '%!PS-Adobe-' で始まり、EPS も同様ですが前にバイナリプレビューのヘッダ C5 D0 D3 C6 が付くことがあります。PostScript は上から下へ実行される完全なプログラミング言語、PDF はランダムアクセスできる静的なオブジェクトグラフ。PDF が PostScript を置き換えた理由そのものです。

よくある壊れ方

  • バイト位置がずれる編集。相互参照テーブルは絶対バイトオフセットを持つので、ファイルのどこかに 1 バイト挿入・削除しただけで、それ以降のエントリが全部無効になります。ビューアはテーブルを作り直して(ファイル全体を走査して 'N 0 obj' のパターンを拾って)対処するので、手で編集した PDF はすっと開かず、警告付きで遅れて開きます。
  • ダウンロードの途中切れ。前方のオブジェクトは残っているので、テーブルを再構築すれば 1〜2 ページは描画できることもありますが、末尾の相互参照テーブルと trailer は失われており、読む側には出発点がありません。確認するのは末尾 1024 バイトに %%EOF があるかどうかです。
  • テキストモード転送。ASCII モードの FTP は FlateDecode ストリーム内の 0D 0A を書き換えます。ヘッダは無傷でパースも通るのでファイルは開き、そのうえで個々のページが真っ白になったりストリームのデコードエラーを出したりします。deflate データが展開できなくなっているからです。
  • 増分更新を間違ったベースにつなげた。PDF は全体を書き直さずに変更を追記できるので、署名や注釈の付いたファイルは元のファイル+前を指す 2 つ目の相互参照セクションという構造になっています。/Prev のオフセットが実際の前の %%EOF の位置と合わないセクションを継ぎ足すと鎖が切れます。それでもヘッダも最終 trailer も無傷に見えてしまいます。
  • 相互参照ストリームを書きながらバージョンを 1.4 と名乗る生成器。圧縮された相互参照ストリームとオブジェクトストリームは PDF 1.5 からの機能です。宣言されたバージョンを額面どおり守る読み手はそれを探しに行かないので、全バイトが正しく揃っているのに文書にはオブジェクトが 1 つも無いように見えます。

この形式の現在地

見た目が変わってはいけない文書を渡す手段として広く通用するのは、30 年経った今も PDF だけです。契約書、請求書、明細、論文、申請書、印刷入稿データ、署名や長期保存が要るものは結局すべて PDF になります。フォントを埋め込み、字の位置をページ上で固定してしまい、読み手の環境に合わせて流し直したりしないからです。逆に向いていないのは、また編集する予定のあるものです。PDF が持っているのは段落ではなく描画命令なので、「PDF を編集する」とは文字の並びから単語を推測し直す作業になります。スマホで読むものにも向きません。固定された A4 ページはちょうど形が合わず、リフローできる EPUB のほうが圧倒的に有利です。派生規格はそれぞれ確固たるニッチを持っていて、長期保存向けの PDF/A はフォントの完全埋め込みを求め外部依存を許さず、PDF/X は印刷入稿用です。仕様は今や Adobe ではなく ISO のもので、ブラウザも自前のレンダラーを積んでいます。何もインストールせずどの端末でも確実に開ける、数少ないファイル形式の 1 つです。

PDF ファイルをこのサイトで開く

どれもブラウザ内で動きます。ファイルが端末から出ることはありません。

関連する形式

PDF と混同しやすい形式です。先頭バイトを見比べてください。

形式先頭バイト拡張子
OLE2 / CFBD0 CF 11 E0 A1 B1.doc
RTF7B 5C 72 74 66 31.rtf
Word 文書(docx)50 4B 03 04.docx

よくある質問

ファイルのマジックナンバーとは何ですか?

ファイル先頭の数バイトで、名前が何であろうとその形式を示すものです。PNG は必ず 89 50 4E 47 で始まり、ZIP は 50 4B 03 04 で始まります。OS もブラウザも file コマンドも、拡張子を信用せずこのバイト列を読みます。だからファイル名を変えても中身の正体は変わりません。

マジックナンバーを自分で確認する方法は?

macOS や Linux なら xxd -l 16 ファイル名 で先頭 16 バイトが表示されます。Windows なら PowerShell で Format-Hex -Path ファイル名 -Count 16 です。あるいはこのサイトのファイル形式判別ツールにドロップすれば、ローカルでバイト列を読んで形式を教えてくれます。アップロードはありません。

2 つの形式が同じマジックナンバーを持つのはなぜ?

一方が他方の上に作られているからです。docx、xlsx、pptx、apk、jar、epub はすべて中身が ZIP アーカイブなので ZIP の署名で始まり、区別するには内部のエントリを見る必要があります。Java の class ファイルと macOS のユニバーサルバイナリはどちらも CA FE BA BE で始まり、直後のフィールドで見分けます。

マジックナンバーがまったくないファイルもある?

あります。XML、HTML、JSON、SVG、CSV といったテキストベースの形式には固定のバイト署名がないため、構造から判別します。先頭の <?xml 宣言、<svg 要素、あるいは { に続く引用符付きのキーなどです。これは確定ではなく推測なので、このリファレンスではそうした形式をプローブ判別として示しています。

マジックナンバーが一致すればそのファイルは安全?

いいえ。わかるのは形式であって、中身が無害かどうかではありません。正規の PDF や docx でも悪意のあるペイロードを含んでいることがあります。特に拡張子とバイト列が食い違うときに真の形式を知るのは有用な第一段階ですが、マルウェアスキャンではありません。

PDF かもしれないファイルをお持ちですか?ファイル形式判別ツールで調べる — マジックナンバーをローカルで読み取ります。アップロードは一切ありません。またはすべての形式を見る。