マクロツイーター

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

dvipdfmx での EPS 画像挿入が最近アレな話

[2014-02-22 追記]

この記事の内容は「実験レポート」的なものです。そこから得られる結論については次の記事を参照してください。

ここでの「実験」では敢えて「間違った設定」の下での動作を調べています。しかし本来はそのような調査はあまり有意義でなく、「間違った設定」での動作は「未定義」であると認識するべきだと私は考えています。事実、本記事で述べられている「実装変更」によって“影響”を受ける(動作が変わってしまう)のは「間違った設定」の使用者に限られ、「正しい設定(ドライバを dvipdfmx にする)」を用いている人にとっては何も変わっておらず(つまり、「graphicx パッケージの仕様通りの動作」をする;実は一部の不具合が解消されている)、その多くは今回の改修に気付いていないと思います。

要するにこの記事に書いた「複雑な話」は普通は全く知る必要がないものです――単に「間違ったこと」をしなければよい、それだけの話ですから。

※ただし、今回の改修について、trim や viewport 指定が無効になるという不具合が判明しています。

「画像の挿入」といえば、今も昔も LaTeX 初心者・初級者にとって最大の難関であるが、どうも最近、「EPS 画像の挿入が、以前は上手くいっていたのに(TeX システムを更新すると)位置がずれるようになった」という話をよく聞くようになった。TeX Forum での角藤氏の発言によると、これは、昨年(2013 年)中に行われた「dvipdfmx が Ghostscript を呼び出す時のオプションの変更」に起因するものらしい。気になったので、少し実験してみた。

dvipdfmx が Ghostscript を呼び出す時のコマンドラインは dvipdfmx の設定ファイルである dvipdfmx.cfg に記述されている。この中の D "〜" と書いてある行の“”の部分が呼出のコマンドラインである。最新の TeX Live 2013 では以下のようになっている(実際は一行)。

rungs -q -dNOPAUSE -dBATCH -dEPSCrop -sDEVICE=pdfwrite -dCompatibilityLevel=%v
  -dAutoFilterGrayImages=false -dGrayImageFilter=/FlateEncode -dAutoFilterColorImages=false
  -dColorImageFilter=/FlateEncode -sOutputFile='%o' '%i' -c quit

TeX Live 2012 ではこの中の -dEPSCrop の代わりに -sPAPERSIZE=a0 というオプションが指定されていた*1。このオプション変更に伴い dvipdfmx の EPS の読込動作が変化するので、graphicx パッケージのドライバ定義 dvipdfmx.def(および xetex.def)にも修正が加えられている。

実験内容

最新の TeX Live 2013 において以下の実験を行った。

  • dvipdfmx で設定を色々と変更した上で 3 種類の EPS 画像を読み込んだ PDF 文書を作り、出力を確認する。
  • 3 つの EPS 画像は(バウンディングボックスの中だけ見ると)同じ図が描かれているが、バウンディングボックスの左下座標値の符号が異なる:img-zero.eps はゼロ(座標 (0,0))、img-posi.eps は正(座標 (100,100))、img-nega.eps は負(座標 (−50,−50))である。
  • dvipdfmx の設定について:
    • dvipdfmx.cfg 中の gs 呼出のオプションが -dEPSCrop(新しい)か -sPAPERSIZE=s0(古い)か。
    • LaTeX 文書中の graphicx パッケージ読込時のドライバ指定が dvipdfmx(正しい)か dvips(間違い)か。さらに、gs オプションが -sPAPERSIZE=a0(旧)の場合は、ドライバファイル dvipdfmx.def について最新のものと古いもの(gs オプション変更前のもの*2)を試した。

実験に用いた LaTeX 文書 imgtest.tex は以下の通り。

\documentclass[a4paper]{article}
\usepackage[dvipdfmx]{graphicx}
\begin{document}
$\leftrightarrow$%
\includegraphics[width=4em,clip]{img-zero.eps}%
$\leftrightarrow$%
\includegraphics[width=4em,clip]{img-posi.eps}%
$\leftrightarrow$%
\includegraphics[width=4em,clip]{img-nega.eps}%
$\leftrightarrow$%
\end{document}

EPS 画像ファイル img-zero.eps のソースは以下の通り。

%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 100 100
newpath 0 0 moveto 100 0 lineto 100 100 lineto
0 0 lineto closepath stroke
%%EOF

バウンディングボックスの内部だけを正常に描画すると以下のような図になる。*3

img-posi.eps は img-zero.eps のソースに含まれる全ての座標値(バウンディングボックスも含む)を 100 増加させたものである。img-nega.eps は同様に 50 減少させたものである。バウンディングボックスの内部だけ描画した場合は img-zero.eps と全く同じ図が得られるはずである。

実験結果

結果の PDF 文書に出力された図の部分を Adobe Reader(最新版)で閲覧した場合の表示を画像として掲載する。なお、SumatraPDF でも全く同じ表示となった。

  • ① gs オプション = -dEPSCrop(新)、ドライバ指定 = dvipdfmx(正)、新しい dvipdfmx.def。
  • ② gs オプション = -dEPSCrop(新)、ドライバ指定 = dvips(不正)。
  • ③ gs オプション = -dsPAPERSIZE=a0(旧)、ドライバ指定 = dvipdfmx(正)、新しい dvipdfmx.def。
  • ④ gs オプション = -dsPAPERSIZE=a0(旧)、ドライバ指定 = dvipdfmx(正)。古い dvipdfmx.def。
  • ⑤ gs オプション = -dsPAPERSIZE=a0(旧)、ドライバ指定 = dvips(不正)。

補足

  • 手許の W32TeX(2013 年 6 月頃の版)でも試してみたが、結果は TeX Live と全く同じであった。
  • W32TeX ではドライバ指定を dvipdfm(非 x)にすることも試したが、結果は ドライバを dvips にした場合と同じであった。
考察
  • ドライバ指定が正しい(dvipdfmx)場合:
    • 新しい方の設定(-dEPSCrop + 新しい dvipdfmx.def)では 3 つの画像が全て正常に出力される(①)。
    • 古い方の設定(-sPAPERSIZE=a0 + 古い dvipdfmx.def)では出力の位置は正しいが、座標が負である領域の描画が欠けてしまう(④)。
    • つまり、gs 呼出のオプションが変更された目的は、この「負の部分が欠ける」という不具合を解消するためであったと思われる。ただし、これにより、ドライバの実装((具体的にいうと、画像読み込みの \sepcial のパラメタ。))を変える必要が生じていて、新しいドライバ実装は古いオプションとは互換性が無い(③)。
  • ドライバ指定が正しくない(dvips)場合:
    • 古い方の設定(-sPAPERSIZE=a0)は、(古い方の設定の)dvipdfmx 指定の場合と同じ結果になる(⑤)。
    • 新しい方の設定(-dEPSCrop)では出力位置がずれてしまう(②)。
    • すなわち、「新しい TeX システムで EPS 画像がずれる」という現象の原因は、ドライバ指定が「正しくなかった」(dvipsdvipdfm が指定されていた)からと考えられる。
まとめ

以上の結果から、普通のユーザへのアドバイスとして次のことが言える。

  • TeX 一式を新しくしたら EPS 画像がずれる」という問題が起こった場合は、改めてドライバ指定を確認しよう
  • ドライバ指定(graphicx のオプション)が誤って dvipsdvipdfm になっていたら、dvipdfmx に訂正しよう。

問題なのは、何か目的があって敢えて不正なドライバ指定(dvips)をしている人(つまりバッドノウハウ屋)である。

  • 「考察」で述べたように、gs 呼出のオプション変更は、EPS 画像読込の不具合(一部が欠ける)を解決するためのものである。
  • ところが、バッドノウハウ屋にとってはこの変更は逆に状態を悪化させる致命的なものになっている。
  • 今後もバッドノウハウへの依拠がどうしても必要であるなら、gs 呼出のオプションを -sPAPERSIZE=a0 に戻す必要が生じる。
  • しかし、この状態では「正しいドライバ」(dvipdfmx)での動作が不正になるので、dvipdfmx.def も古いものに差し替える必要がある。

バッドノウハウを捨てられないかを真剣に検討すべきなのかも知れない。

*1:変更があったリビジョンは 30175。

*2:リビジョン 9280。

*3:垂直と水平の直線に関しては、その太さの中心にバウンディングボックス境界が通っているので、ボックス外がクリップ(消去)されることによって、線の太さが半分になったように見えている。