マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

dvipdfmx で画像する時に色々とアレな話

取りあえず、メモとして要点をまとめておく。

  • 特に明示する場合を除き、EPS 形式のことは考えない。
  • dvipdfm? ああ、懐かしいね…。
「標準の方法」は何か

“普通の環境”において、初級者に奨めるべき“標準”の方法は何か? 特に bbox を取得する各種の方法のうちどれを選択するかが問題になる。

  • 「extractbb の自動起動を有効にする」でおk。
    • W32TeX では自動起動は既定で有効になっている。
    • テフライブではなっていないので各自設定が必要。
      →そのうち既定で有効になるよ!
  • どうしても自動起動が“生理的に受け付けない”人のための代替案:
    事前に extractbb を手動で起動して .xbb ファイルを作成しておく。
    • ビルド用のバッチ処理(make 的な何か)の中に組み込んでおく(結局「自動」になる)のが賢明。

補足:

  • テフライブで extractbb の自動起動が認められてない理由:
    • dvipdfmx のドライバの動作では、.xbb は画像ファイルと同じディレクトリに存在する必要がある。
    • なので当然、extractbb はそのディレクトリに .xbb を書き出す。
      →つまり、画像ファイルのあるディレクトリならどこでもファイルを書き出そうとする。
    • これは、paranoid 制約(texmf.cnf の openout_any 変数)に違反している。
  • ドライバ v4.02 [2014/07/02] で取られた対策:
    • そもそも .xbb ファイルを書き出すのを止める。
    • extractbb は .xbb の内容を標準出力に書き出し(-O オプション指定)、TeX エンジンはパイプ入力(\input"|コマンド")を用いてそれを読み込む。
      →これで、「どこにでもファイルを出力できる」必要性が無くなった。
    • なので、extractbb を「paranoid 制約を守る」ように改修した。
      →つまり、現在ディレクトリの外にある画像ファイルについて .xbb ファイルを出力することが禁止された。
    • これで、テフライブのポリシーに適って、extractbb を“特別許可リスト(shell_escape_commands 変数)”に含められる(はず)。
  • 補足の補足:
    • .xbb が既に存在する場合は extractbb 実行は行わない(後方互換維持)。
    • 邪魔な .xbb ファイルが消え去ってハッピー。
    • 「パイプ入力」は当然 shell escape 機能の一部である。つまり、“\write18”でのコマンド実行と同じ制限が掛けられている。
      (だから特別許可リストにないと extractbb からの入力は不可。)
    • ちなみに、extractbb の -O オプション自体はかなり昔から存在した。
    • ところが、少なくとも Windows 版テフライブ 2014 では、TeX エンジンのパイプ入力でコマンドラインに引数がある場合の動作に不具合(?)があるようで、最新の W32TeX のバイナリではこれが修正されている。
    • つまり、ドライバファイル(dvipdfmx.def)だけ最新にしてもダメ、ということ。
bb オプションが(あまり)役に立たない話

bbox の取得について、\includegraphics 命令の bb オプションに bbox の値を直接指定するという方法がある。ただし、これは「extractbb を起動すること」の代用にはなりそうになくて、用途は限られている、という話。

  • bbox の値は、各画像ごとに予め決まっている。文書作成者が挿入時に勝手に決められるものではない。つまり、「bbox には“正解”がある」。
  • 大事なことなので繰返し:「bbox には“正解”がある」
  • なので、bb オプションには“正解”の値を指定しなければならない。“間違い”の値を指定した時の動作は未定義
    • 信じられない人は、graphicx パッケージのマニュアル嫁。
    • 最近の TeX 環境においては、“間違い”の値を指定したために不可解な動作が起こる例が実際に存在する。
    • bb オプションではなくて .xbb ファイルを利用する場合も、当然、その中に記された bbox の値は正解である必要がある。
  • 大問題:正解の bbox の値を知るのは“普通の人”には極めて難しい。
    • さらに【dvipdfmx の独自規則】が色々と絡んできて、これが厄介。
    • 外部ツールが判断する“正解”と dvipdfmx が判断する“正解”が食い違うことがあるので。もちろん、bb に指定すべきものは「dvipdfmx の正解」の方である。
  • ビットマップ画像の場合:
    • この場合、常識的に、“普通に画像をビューアで開いた時に見えるもの全体”が bbox である。
    • ただし注意: bb オプションの数値の単位はポイント(bp)である。ピクセルではない。
      • 信じられない人は、マニュアル嫁。
      • 1in = 72bp = 72.27pt。
      • そもそも bbox は「物理的な寸法」で表されるものである。
    • ビットマップ画像の「物理的な寸法」を得るには? →解像度(dpi 値)の情報が必要。
      • OS 標準のツールを使うとピクセル単位のサイズは比較的容易に解るが、解像度の情報を得るのは簡単じゃないぞ。
        (例えば ImageMagick の「identity --verbose」を使うと判る。)
      • 解像度の情報は無い場合もあり、その場合は 72 dpi と解釈する。【dvipdfmx の独自規則
        ↑ただし pdfTeX も同じ規則。
    • 実は昔(2007 年 5 月)の dvipdfmx では、「不正な解像度を仮定して算出した」bbox でも問題がなかった。
      • ちなみに、解像度を 72 dpi であると仮定すると、bp 単位の数値とピクセル数が一致する(1in = 72px = 72bp)。
      • 美文書第 4 版(2007 年 1 月)ではこれを前提として、bb オプションにピクセル数を指定することが説明されていた。
      • 解像度に関する“粗略さ”が失われたのは、ビットマップ画像に対する部分挿入(viewport/trim オプション)がサポートされたことに対する代償。*1
  • PDF 形式画像の場合:
    • PDF 画像でややこしいのは、bbox に相当する概念として、ちょっとずつ用途の異なる“ナントカBox”が複数存在する、ということ。
    • 5 つの“ナントカBox”のどれを bbox として採用するかはソフトウェアの判断に委ねられる。つまり、dvipdfmx とその他のツールで正解が異なる可能性がある。
    • “普通に画像をビューアで開いた時に見える領域”は多くの場合に(dvipdfmx の判定する)正解と一致するが、そうではない場合も存在する。
    • 【dvipdfmx の独自規則】は、PDF の仕様と齟齬を起こす、かなり凶悪なものである。
  • では何故、extractbb を用いた場合は上手くいくのか?
  • 答え:extractbb は dvipdfmx の付属ツールであり、常に dvipdfmx と同じ“正解”を出すため。
    • 結局、bb オプションに指定する正解の値を簡単かつ確実に得る唯一の方法は、extractbb を起動してその出力の値を見ることである。
    • なので、この方法が有効な場面はかなり限られる。
      「extractbb の自動起動」と「.xbb ファイルの配置」の両方を嫌う場合、とか。
    • extractbb の間接利用以外の方法でも“場合によっては”正解の値が得られるだろう。ただ、“どういう場合にどういう方法が使えるか”を把握するのは〈特に初級者には)かなり困難だと思われる。

補足的な何か。

  • ところで、「画像挿入時に bbox を別の値で“上書き”する」のに bb オプションが使えない、というのは graphicx パッケージの「仕様」である。
  • 実際には、「bbox の値を上書き」する機能を実装することは可能である。
    • さらに、実は、現在存在する全てのドライバの版において、PDF 画像においては、bb オプションを用いて bbox の上書きが“実装上は”可能である。
    • PDF 画像の bbox は元々「これが唯一絶対の正解」というものが無く、また、dvipdfmx が定める正解はアレなので、PDF 画像に対しては「bbox の上書き」の機能は是非とも欲しい。
    • といっても、「graphicx の仕様を変更する」のは他のドライバに影響が及ぶので無理。
  • そこで、拡張パッケージを別途用意して、それに「bb オプションで bbox を上書き可能にする」という機能を持たせればよいのではないか。
    • もちろん、このパッケージの実装は、ドライバ(dvipdfmx.def)の実装に常に追随させる必要がある。
    • ビットマップや EPS 形式画像までサポートしようとするとかなり面倒なことになる。
DecodeParms だとアレする件

PDF 中のストリームデータの圧縮については、圧縮率を上げるための様々な前処理がサポートされている。これを有効にするにはストリームのメタデータとして DecodeParms というパラメタを指定することになっている。ところが、dvipdfmx/extractbb はこの処理に対応してないため、PDF バージョンが 1.5 以上である PDF 画像ファイルの一部について、エラーを表示して終了してしまう
(→そのうち解決する!(補足参照))

  • extractbb がが扱えないファイルは dvipdfmx も扱えない。従って、この場合、bb オプションを補って extractbb の使用を回避するという手段は無意味である。
  • 要するに、「dvipdfmx はそのファイルに対応していない」ということだから、画像ファイルの方に手を付けるしかない。
    • 例えば、qpdf 等の PDF 操作ツールを使って、「ストリームの圧縮を全て解除する」変換を行う。変換後のファイルは元のものと全く同じ bbox の情報を持っているはずである。
      (dvipdfmx で挿入する際に再びオブジェクトは圧縮されるので、出力文書のサイズが肥大化することはない。)
    • 或いは、当該の PDF ファイルが「自分で出力したもの」だった場合は、出力ソフトウェアの設定を変更してファイルを作り直すことも考えられる。
      (多くの場合、PDF バージョンを 1.4 にすれか、または圧縮を非適用にすればよい。)

補足:

複数ページの PDF がアレな件

現状では extractbb は複数ページの PDF ファイルに対応していない、という話。

  • dvipdfmx 自体は「複数ページの PDF ファイルの指定のページを挿入する」という操作に対応している。
  • なので、page オプションが使用可能である。
  • 問題は extractbb の方で、これは複数ページの PDF ファイルを指定すると、常に先頭のページ(画像)の情報を返してしまう!
    • マニュアルにハッキリとそう書いてあるぞ!
  • つまりは……
    • 単一ページしかない PDF ファイルであれば問題なし!
      • 専ら画像として使う PDF は大半がそうだろう。
    • 全部のページの bbox が同一であることが予め解ってるなら特に気にする必要なし!
      • 単に page を指定すれば済む。
      • 普通の PDF 文書の中の「特定のページの特定の領域の内容を別の文書に挿入したい」という場合、「普通の文書」の PDF は大抵は全ページが同じ大きさだろう。
    • 各ページの bbox が異なりうる場合は……残念
      • ただ、そんな感じの PDF ファイルってなかなか無さそう。
      • 複数の画像を敢えて一つの PDF ファイルに“束ねて”管理している、とかいう場合。
  • 厄介なのは、「extractbb が封じられた状態で“正解”の bbox を得る」のは激しく困難なこと。
    • 先の節で書いた通り!
  • 姑息な手段は:
    • 無難な方法:前もって、PDF 操作ツール(qpdf 等)を利用して指定のページの画像を別ファイルに取り出しておく。
    • これだと、“束ねる”管理をする利点は消失してしまう(残念だね)。
    • ただし、“束ねた”ファイルを作成したのが自分であるなら、その bbox についての既知の情報を利用して問題を回避できるかも。
      • 例えば、ファイル作成時に「MediaBox しか指定していない」ならば、各ページについて 5 つのナントカBoxは全部同じ値のはずで、それなら当然、【dvipdfmx の独自規則】でもその値が正解の bbox になるはず。
      • この場合、「MediaBox の値を得る」ためのツール(pdfinfo 等)を使って当該ページの bbox を得て、それを bb に指定することで正常に処理させることができる。

根本的な対策は、もちろんコレ。

  • extractbb を複数ページの PDF に対応させる改修を行う。
    • ページ番号指定のオプションを新設して、そこで指定されたページの bbox を出力する。
  • 昔の dvipdfmx ドライバの動作では、実はこれでは解決しない。
    • 同一の PDF 文書の 1 ページ目と 2 ページ目を順に挿入しようとすると……
    • .xbb ファイルが衝突してしまう。
    • 既存のファイルを上書きするのはアレだし、何らかの工夫が必要そう。
  • しかし現状のドライバ実装では話はとっても簡単。
    • .xbb ファイルを作らないため、元のファイル名が同じでも全く影響を受けない。

*1:昔の dvipdfmx の実装ではビットマップ画像の挿入の special 命令については、bbox の値を全く無視していた。