PDFのページを入れ替える・抜き出すときに起きること
PDFから要らないページを消せば軽くなる、と思いがちだが、そうならないことがある。測ってみたら、5ページから1ページ抜き出してサイズが99.9%のままだった。
同じ5ページから、1ページだけ抜き出す
2種類の5ページPDFを用意した。どちらも同じ大きさの画像を1つ持っている。違うのは、その画像をどのページが使っているかだけだ。
- A: 5ページ全部が同じ画像を表示する
- B: 1ページ目だけが画像を表示し、残り4ページは文字だけ
それぞれから1ページを抜き出した結果がこれだ。
| 元ファイル | 抜き出したページ | 出力サイズ | 画像オブジェクト | 元の何% |
|---|---|---|---|---|
| A(全ページで共有) | 3ページ目 | 1,594,985 B | 1 | 99.9% |
| B(1ページ目だけ) | 3ページ目 | 865 B | 0 | 0.1% |
| B(1ページ目だけ) | 1ページ目 | 1,594,992 B | 1 | 99.9% |
同じ「1ページを抜き出す」操作なのに、865バイトと1.59MBに分かれた。
運ばれるのは「そのページが参照しているもの」
理由は、PDFの構造そのものにある。
PDFの中身は番号の付いたオブジェクトの集まりで、ページはそれらを番号で参照している。ページを抜き出すとき、ツールが運ぶのはそのページが参照しているオブジェクトだ。ページそのものは、実は驚くほど小さい。
Bの3ページ目は文字しか参照していないので、運ばれるのはページと文字の描画命令だけになる。結果が865バイトだ。
一方、Aの3ページ目は画像を参照している。その画像は5ページで共有されていたが、共有されていたかどうかは関係ない。1ページでも参照していれば、丸ごと運ばれてくる。
サイズはページ数では決まらない。そのページが何を指しているかで決まる。
「軽くするために削る」は当たらないことがある
この性質は、実務でそのまま効いてくる。
全ページに同じロゴが入っている書類は、何ページ消しても軽くならない。残った1ページがロゴを参照している限り、ロゴは付いてくる。
逆に、重い図面や写真が特定のページにだけ入っているなら、そのページを外した瞬間に劇的に減る。 上の表の865バイトがそれだ。
どのページが重いかは、見ただけでは分からない。ページ数やページの見た目と、中身の重さは一致しない。実際に抜き出して測るのが一番早い。
回転は見た目を変えるだけ
ページの回転は、まったく別の性質を持っている。
同じPDFを0度・90度・180度にして、中身を比べた。
| ページサイズ | /Rotate | 文字の描画命令 | |
|---|---|---|---|
| 回転なし | 595 × 842 | 0 | 1 0 0 1 100 700 Tm <68656C6C6F> Tj |
| 90度 | 595 × 842 | 90 | 同じ |
| 180度 | 595 × 842 | 180 | 同じ |
変わったのは /Rotate の数字だけ。 ページの寸法も、文字を置く座標も、1バイトも動いていない。
/Rotate は「このページを表示するとき、これだけ回してから見せてください」という指示にすぎない。中身は最初の向きのまま置かれていて、読む側が回している。
だから回転してもサイズはほとんど変わらないし、文字は文字のままだ。回転したPDFでも検索やコピーができるのはこのためで、画像として焼き直しているわけではない。
ついでに、この仕様から素直に出てくる注意がある。回転は足し算になる。 すでに90度回っているページにもう90度足せば180度だ。0度から始まる前提で上書きすると、見た目が意図と合わなくなる。このサイトのツールは足す側で実装している。
まとめ
- ページを抜き出すと、そのページが参照しているものが一緒に来る。
共有されていた画像でも、1ページ残れば丸ごと残る
- ページ数とファイルサイズは比例しない。 削っても減らないことがあるし、
1ページ外すだけで激減することもある
- 回転は表示の指示が1つ増えるだけ。 中身は動かない
軽くしたいなら、ページを消すより何が重いのかを見つけるほうが先だ。
計測の条件
pdf-lib(このサイトのツールが使っているもの)で、900×600のノイズ画像を埋め込んだA4・5ページのPDFを2種類作り、copyPages で1ページずつ抜き出した。画像オブジェクトの数は、生成されたPDFのバイト列から /Subtype /Image を数えた。回転の比較では、ページの内容ストリームを展開して描画命令を取り出し、文字列として比べた。