Acetaminophen’s diary

化学に関すること,TeXに関すること,ゆきだるまに関すること。

LaTeX で PDF の一部だけ表示したい(1)

ただいま改訂中です。ところどころ作業に伴いリンク切れや説明不足が生じていますが、ご了承ください…(2015-08-15)

LaTeX で graphicx パッケージを使っていて

余白がある PDF ファイルの一部だけ、余白を切り取って表示したい

と思ったことはないでしょうか。例えば、Excel でグラフを作成して PDF 形式で保存するとデフォルトでは A4 サイズの PDF が生成し、もれなく余白が付いてきます。このような Excel グラフを作成して \includegraphics したいと思っても「そのままでは余白が大きくて不満」という質問は、最近も TeX Forum に寄せられています

こうした場合は、(上記サイトでの私の回答にもありますが)pdfcrop という TeX Live や W32TeX の付属ツール*1を使って予めトリミングするのが非常に簡単です。ただし、pdfcrop は Perl がインストールされていなければなりません。TeX Live (Windows) には Perl が内蔵されていますし、Unix 系 OS ならば Perl が標準で使えるはずですが、W32TeX ユーザの方は pdfcrop がそのままでは使えません。そこで

のいずれかを試してみてください。そのうえで

$ pdfcrop graph.pdf

あるいは

$ tcpdfcrop graph.pdf

のように実行すれば、きっとうまい具合にまっさらな余白を切り取った新しい PDF (graph-crop.pdf) が出てくるでしょう。

f:id:acetaminophen:20150719021613p:plain

…とまあ、これがベストプラクティスであることは間違いありません。pdfcrop(または tcpdfcrop)が出力した PDF を \includegraphics すれば、バグがない限りどんな場合でも必ずうまくいきます。しかし、中には

pdfcrop せずに直接 LaTeX 側でなんとかならないの?

と思う方もいるでしょう。今回の記事では、その方法を考察することにします。

 

前提知識と本記事で扱う範囲

本記事では「BoundingBox(バウンディングボックス)」という単語が頻出しますので、まずその基本的な意味を確認します。

BoundingBox とは、非常に大雑把にいえば「画像のサイズ」を表すものです。これは画像の左下・右上の (x, y) 座標の組として表され、単位は基本的に bp(ビッグポイント;1bp = 1/72in)です。これは EPS/PDF/PNG/JPG 等いかなる画像ファイルにも存在する概念で、TeX 自身は画像を貼り付ける際にこの BoundingBox 情報をもとにスペースを確保します。このとき「画像に実際に何が描かれているか」には無頓着です。なぜなら、TeX は「組版ソフトウェア」であり、スペースさえ確保すれば文章を綺麗に配列することができるからです。

この BoundingBox は、それぞれの画像ごとに「正解の値」が決まっています*2。そこで私たちユーザは、使用するドライバに合わせた適切な BoundingBox の値を、ドライバに教えてあげる必要があるのです。本記事では PDF 形式の画像ファイルに絞り、その仕組みと実用法を理解しようというわけです。なぜなら、PNG/JPG といったビットマップ画像については比較的簡単に編集できる*3わけですが、PDF は編集ツールが限られており、その仕様の複雑さとあいまって非常にヤヤコシイことになっているからです。また、特に明示しない限り単一ページ PDF を仮定します。これは、結局のところ複数ページ PDF は各ページごとにそれぞれ BoundingBox があるということ以上の特筆性がないからです。EPS は放置です(そもそも最近なら EPS に詳しい人しか使わないはず)。

本記事の前提として「すべて理解することは必ずしも必要ではないが、読んでおくと一層背景理解が深まる」と思う記事を挙げておきます。

最近サブブログに関連記事を大量に出しました。

さらに、それ以前に書かれた ZR さんの記事もあります(上で並べた私の記事を書く際には、大いに参考にさせていただきました)。

多数挙げましたが、本記事で特に解説することなく前提とする知識は以下だけです。

  • graphicx パッケージを使うときは「ドライバ指定」に注意する
    • pdflatex を使うなら pdftex である(ただし省略可)
    • platex + dvipdfmx を使うなら(dvipdfm でなく)dvipdfmx である
  • graphicx パッケージの bb= や viewport= というオプションの存在意義は
    • bb= はユーザが BoundingBox の値を指定するため
    • viewport= はユーザが一部だけ見せたいと思う範囲を指定するため
    であり、したがって「画像の一部表示」という目的に用いるべきは(bb= でなく)viewport= である
  • graphicx パッケージの bb= にしろ viewport= にしろ、単位は(px ではなく)bp でなければならない

これ以外の知識については適宜本記事で説明しつつ、必要に応じて上記リンクを貼ることにします(上記3点は「常識である」としないと余分な説明が増えてしまいますし、他はかなりヤヤコシイ話を含むので「常識」とするには値しないでしょう)。

 

PDF ファイルの通称「ナントカBox」

本記事では PDF の BoundingBox に絞って説明すると先ほど述べましたが、これだけで結構複雑です。まず、PDF の仕様書(1.3 以降ならどれでも構いません)をみてみると、BoundingBox にあたりそうなものが5種類もあるんですね。ZR さんの記事(ナントカBox の話(2);上記リンク集より)の“訳”をさらに要約すると

  • MediaBox:用紙(等の媒体)に実際に印刷される領域;必ず明示される
  • CropBox:最も一般的な意味での、「そのページの(外形を込めた)内容」を表す領域;明示されていなければ MediaBox と同じと解釈する
  • BleedBox:専門的な印刷工程における、「断ち落としサイズ」に相当する領域;明示されていなければ CropBox と同じと解釈する
  • TrimBox:専門的な印刷工程における、「仕上がりサイズ」に相当する領域;明示されていなければ CropBox と同じと解釈する
  • ArtBox:PDF 文書を画像として用いる場合の、「その画像の(外形を込めた)内容」を表す領域;明示されていなければ CropBox と同じと解釈する

このように仕様書に書かれています。最もメジャーなのは MediaBox で、これは必ず PDF に明示されているうえ、一般人が最も目にする「用紙サイズ」はこれのことでしょう。次にメジャーなのが CropBox で、これは PDF ファイルを Adobe Reader 等の PDF ビューアで開いた場合に表示する領域です。この他にも3つの Box があり、結局「いったい BoundingBox とは5つのうちどれなのか」というのが PDF では特に問題になるのです。

 

PDF の ナントカBox を全て知る方法

これら5つの Box をすべて一度に調べる方法が、pdfinfo というツールです。これは XpdfPoppler の一部で、TeX Live (Windows) や W32TeX には付属していますし、Unix 系ならパッケージ管理システムでインストール可能です。たとえば

$ pdfinfo -box hoge.pdf

のように実行すると、PDF の ナントカBox 情報が表示されます。

なお、PDF の仕様書では「MediaBox をほかの Box がはみ出す場合は不正であるので、そのはみ出した Box は MediaBox に収まるようにクリップされる」と定められています。pdfinfo はこの仕様に忠実に従っているため、必ずしも PDF ファイルに書かれたとおりの値が返ってくるとは限りません。doraTeX さんによる記事で公開された「改変版 pdfinfo」(ここでは pdfinfo-extractbb と呼びます)を使えば、そのクリッピングが行われているかどうかまで判定することができます。詳細は、最初に挙げたリンク集の「BoundingBox がとにかくややこしい話(1), (2)」で私が説明しています。

 

実際に TeX が使う BoundingBox はどれなのか

先ほど述べた通り、BoundingBox には画像ごとに正解が存在します。では、PDF の場合どれが正解なのでしょうか。…これはドライバによって異なるので、個別に説明する必要があるのです。例に使用する PDF は以下のようなものです:

f:id:acetaminophen:20150815220458p:plain

各 ナントカBox がわかりやすいように、実際に PDF に与えた ナントカBox と一致するように赤枠を描画し、その Box の頭文字を左下と右上に書き込んであります。pdfinfo-extractbb で調べてみると以下のとおりです。

  • boximage-a1-catbm.pdf
------------------------------------------------------------------------
Page    1 MediaBox:     0.00     0.00   300.00   300.00
Page    1 CropBox:     30.00    30.00   190.00   200.00   [dvipdfmx BB]
Page    1 BleedBox:     5.00    45.00   170.00   210.00
Page    1 TrimBox:     70.00    20.00   220.00   180.00
Page    1 ArtBox:      60.00    10.00   140.00   220.00
------------------------------------------------------------------------
  • boximage-a2-atbm.pdf
------------------------------------------------------------------------
Page    1 MediaBox:     0.00     0.00   300.00   300.00
Page    1 CropBox:      0.00     0.00   300.00   300.00   [Implicit]
Page    1 BleedBox:     5.00    45.00   170.00   210.00
Page    1 TrimBox:     70.00    20.00   220.00   180.00
Page    1 ArtBox:      60.00    10.00   140.00   220.00   [dvipdfmx BB]
------------------------------------------------------------------------

この例示 PDF をもとに、いくつかの実験を行っていきます。

1. pdfLaTeX の場合の BoundingBox(PDF が正常な場合)

これは ZR さんの ナントカBox の話(2) に書かれていますが、デフォルトは CropBox です。しかし、graphicx パッケージの pagebox= というオプションを利用すれば、好きな Box をユーザが指定可能です。

初めに、すべての Box が異なる値で明示された boximage-a1-catbm.pdf を使ったソースを処理した結果でどの Box が選ばれたかを判定します。ついでに、width= の前に pagebox=****box, を加えてから処理したものも並べておきます。これらの結果を見比べれば「全て明示されたときは CropBox が採用される」ことが一目瞭然です。

  • BB-a-01-pdfLaTeX-TL2015.pdf の1ページ目より

    f:id:acetaminophen:20150816181722p:plain

では CropBox が明示されていない場合はというと、取り込む画像を boximage-a2-atbm.pdf に変えればよいわけで、この結果は MediaBox が採用されることを確認できます。ここで MediaBox が採用されたことと、PDF の仕様書の「CropBox が非明示ならば MediaBox と同じと解釈される」という規則を組み合わせると、結局のところ今回も採用されたのは CropBox だと言ってよいわけです。

  • BB-a-01-pdfLaTeX-TL2015.pdf の2ページ目より

    f:id:acetaminophen:20150816181736p:plain

2. LuaLaTeX の場合の BoundingBox(PDF が正常な場合)

LuaLaTeX は pagebox= オプションが使えないということを除いて pdfTeX と同一です(なお、pagebox= が使えない問題はちょっとしたトリックで回避でき、例示ソースではそのトリックを使っています)。つまり、現状では「常に CropBox が使われる」ということもできます(トリックを使わないかぎり)。先ほどのソースは全く同様に LuaLaTeX でも処理できて、同じ結果を確認できます。

3. XeLaTeX + xdvipdfmx の場合の BoundingBox(PDF が正常な場合)

XeLaTeX (+ xdvipdfmx) は先に挙げた ZR さんの ナントカBox の話(2) にあるように、pagebox= オプションが使えないということを除いて pdfTeX とほぼ同一です。つまり、現状では「常に CropBox が使われる」ということもできます(LuaLaTeX のようには簡単なトリックで回避することもできません)。ただし、注意すべき点があります。いま、ここで「ほぼ」という言葉を付けました。これは「領域確保に使われるのは CropBox だが、これが実際に描画される領域とは一致しない」ことを意味します。これは XeLaTeX + xdvipdfmx という処理系統の特性で「XeLaTeX は CropBox を確保するのに xdvipdfmx が描画するのは後述する “dvipdfmx が選ぶのと同じ ナントカBox の内側” だけである」という奇妙な挙動によるものです。

  • BB-a-03-XeLaTeX-TL2015.pdf の全ページより

    f:id:acetaminophen:20150816181752p:plain

 

…闇が見えてきたあたりで、次回に続きます

*1:紛らわしいことに pdfcrop には2種類あり、CTANSourceForge にあるものは全く別物です。ここで言っている pdfcrop は CTAN の方です。

*2:ただし少々ややこしいことに、その正解はドライバによって異なる場合があります。例えば、昔使われていた dvipdfm と現在主流の dvipdfmx では BoundingBox の値が異なるということが知られています。実際に dvipdfm が使う正解の値を返す ebb というプログラムと dvipdfmx が使う extractbb というプログラムに PNG ファイルを読ませると、異なる値が返ってくるはずです。

*3:Windows なら「ペイント」でも結構です。