Hatena::ブログ(Diary)

アセトアミノフェンの気ままな日常

2015-07-26

pdfcrop はなぜ PDF をクロップできるのか

本題の前に、メインブログの更新が滞っている… しかし、これは現在進行形の「pagebox オプションを dvipdfmx や XeLaTeX (xdvipdfmx) で使えるようにする」という改修が安定するのを待っているためである*1

pdfcrop が PDF の余白を「確実に」クロップできる理由

以前ツイートしたが、もう少し詳しく「あれだけ ナントカBox のヤヤコシイ事情があるのに、pdfcrop は余白を確実にクロップできるのか」に絞って考えたい。TeX 注意!*2
さて、Perl スクリプトである Oberdiek さん作の pdfcrop や、僕が作っている tcpdfcrop が生成するソースのうち、必要最小限の部分を抽出してみよう。pdfcrop で TeX エンジンを pdfTeX または LuaTeX に指定した場合、あるいは tcpdfcrop を使った場合に経由する中間 plain TeX ソースの最低限の部分は以下のようになる*3

%#! pdftex / luatex
\pdfoutput=1
\def\proc[#1 #2 #3 #4]{\setbox0=\hbox{\pdfximage page 1 mediabox{test-1.pdf}\pdfrefximage\pdflastximage}
\pdfpagewidth=\dimexpr#3bp-#1bp\relax \pdfpageheight\dimexpr#4bp-#2bp\relax
\pdfhorigin-#1bp \pdfvorigin#2bp \ht0=\pdfpageheight \shipout\box0\relax}
\proc[302 393 566 564] % from Ghostscript bbox device
\end

同様に、pdfcrop で XeTeX を指定した場合は以下のような plain TeX ソースとみてよいだろう。

%#! xetex
\def\proc[#1 #2 #3 #4]{\setbox0=\hbox{\XeTeXpdffile test-1.pdf page 1 media\relax}
\pdfpagewidth=\dimexpr#3bp-#1bp\relax \pdfpageheight=\dimexpr#4bp-#2bp\relax
\shipout\hbox{\kern-1in\kern-#1bp\vbox{\kern-1in\kern#2bp\ht0=\pdfpageheight\box0}}}
\proc[302 393 566 564] % from Ghostscript bbox device
\end

いずれの場合も、test-1.pdf という PDF ファイルの「描画されている範囲」を gs の bbox デバイスで取得して \proc の引数として与えている。ここで、以前説明した「gs の bbox デバイスはデフォルトで MediaBox に対する相対位置を返す」という事実を踏まえると、pdfTeX / LuaTeX / XeTeX で PDF ファイルの ナントカBox を使うときに採用すべき値は、まぎれもなく gs のデフォルトに合わせなければならない。すなわち gs の bbox が mediabox を使うから TeX も mediabox を使わなければならない。そこで、中間ソースには mediabox あるいは media という単語が見えることに納得いくだろう。このように mediabox と指定することで、gs と TeX の間で選ばれる Box の整合性を保証することができるのだ!

もうひとつ、MediaBox が都合がよい理由も考えておきたい。MediaBox はほかの Box と異なり、常に明示されることが PDF の仕様書で定められている。そのうえ、pdfinfo や extractbb などどんなツールを使っても常に MediaBox については同じ値が返ってくる(ほかの Box だとすると「MediaBox はみ出し不正」の扱い方の差でクリップされたりされなかったりする)。これらの理由から、一貫して MediaBox を使うのは安全なのだ。

*1:ありがたいことに、記事1, 2本目執筆後に角藤先生がはじめに dvipdfmx を、続いて XeLaTeX を拡張してくださった。さらにもう一つ LuaLaTeX について不思議な挙動が見つかったので、2回分の記事の内容を含めてより正確な記述に改めようとしているところ。

*2:なお、僕自身も以下に例示する plain TeX ソースは完全には理解しておらず、とりあえず pdfcrop が実際に作るソースをどんどん削っていき、残った最小部分を簡単に書いただけに近い。

*3:このソースは大雑把に「PDF の余白分だけページサイズを縮小し、必要な部分だけが収まるように全体をシフトする」という内容である。余白をクロップせずにページサイズ維持したい場合のソース例はこちらが参考になる。