LaTeX: graphicx と color の危険な関係

  • 47
    いいね
  • 1
    コメント

前提

  • LaTeX文書をdvipdfmxを使ってPDF文書に変換している。
  • graphicx(または graphics)パッケージを利用している。
  • colorパッケージを利用している。または何かのパッケージが内部でcolorパッケージを読み込んでいる可能性がある。

問題

  • graphicxパッケージの挙動が不正になる(例えばEPS画像の位置がずれる、出力されない)ことがある。
  • 原因を調べた結果、graphicxパッケージのドライバ指定が間違っていること(参考)に気付いた。
  • そこで、graphicxパッケージに dvipdfmx オプションを追加する対処を行ったが、挙動が変わらない。

対策方法

colorパッケージにも dvipdfmx オプションを効かせる必要がある。そのため、パッケージではなく、文書クラス指定\documentclass)のオプションにおいて dvipdfmx を指定する。これで、colorやgraphicx、および他のほぼ全てのパッケージについて、dvipdfmx オプションが(有効であれば)適用される。

\documentclass[a4paper,dvipdfmx]{jsarticle}% ここで指定
%......
\usepackage{graophicx}% dvipdfmx は自動的に有効になる
%.....
\usepackage{color}% dvipdfmx は自動的に有効になる

補足

本記事の昔の版では、上記の方法のほかに、「colorパッケージにも dvipdfmx を追加する」という方法を紹介していた。

(非推奨)
\documentclass[a4paper]{jsarticle}
%......
\usepackage[dvipdfmx]{graophicx}% これは対処した
%.....
\usepackage[dvipdfmx]{color}% ここにも dvipdfmx を入れる

しかし、「graphicxやcolorを内部で読み込むパッケージ」を内部で読み込むパッケージ(ややこしい…)を利用している場合は、この方法では失敗する(Option clash のエラーが発生する、結局不正なドライバが使われる、等)可能性がある。文書クラスでドライバ指定を行う方法の方が安全であるため、そちらの方法を推奨する。

詳細

※以下では、dvipdfmxを利用していることを仮定する。

colorパッケージも「ドライバ依存」である

graphicxパッケージが「ドライバに依存」することは有名であるが、実は colorパッケージもドライバに依存する。

例1
% dvipdfmx を利用するならドライバ指定が必要
\usepackage[dvipdfmx]{color}

多くのTeX配布では、DVI出力の場合のドライバの既定値は dvips となっている。なので、以下の記述は不正である

例2(不正)
% dvipdfmx を使うのに...
\usepackage{color}% ドライバは既定値の dvips

ところが現状では、colorパッケージについては、dvips ドライバを指定してもdvipdfmxでの動作には表面上の問題が全く起こらない。このため、colorのドライバ指定については無頓着なユーザも多いと思われる。
※「実際には問題ない」ことを利用して敢えて「不正なドライバ」を指定するというバッドノウハウが行われることもありえるが、ここではそれは措いておく。

graphicxとcolorはドライバを「共有」している

ところが、colorとgraphicxを同時に使うと話が複雑になる。

例3(不正)
% dvipdfmx なのか dvips なのか、はっきりしろ!
\usepackage[dvipdfmx]{graphicx}% ドライバは dvipdfmx
\usepackage{color}% ドライバは既定値の dvips

ここではドライバ指定が不正(dvips)なのはcolorパッケージなので、普通に考えるとcolorパッケージの命令の動作が不正になりそうである。しかし、前述の通り、実際にはそこでは問題は起こらない。その代わりに、正しいドライバ指定(dvipdfmx)であるはずのgraphicxパッケージの命令(\includegraphics 等)の動作が不正になる、という不可解な現象が起こってしまう。

その理由は、colorとgraphicxの両パッケージの実装にある。

例1のソースコードを実行すると、LaTeXは以下のように動作する。

  • まず、colorパッケージのプログラムが書かれたファイル(color.sty)を読み込む。
  • 次に、colorパッケージの「dvipdfmxに依存する部分」のプログラム(これが「dvipdfmx用のドライバ」である)が書かれたファイル(dvipdfmx.def)を読み込む。

ところが実は、「colorパッケージのdvipdfmx用ドライバ」が書かれたファイル dvipdfmx.def には「graphicxパッケージのdvipdfmx用ドライバ」のプログラムも一緒に書かれているのである。すなわち、例えば \usepackage[dvipdfmx]{graphicx} が実行される際は、graphicx.sty(と graphics.sty)の他に、この dvipdfmx.def というファイルが読み込まれる。この事情は他のDVIウェアのドライバについても同じで、要するにgraphicxとcolorはドライバを共用しているのである。

この結果、例3のようなソースコードを実行すると以下のような不可解な結果になるのである。

  • graphicxパッケージのプログラムのファイル(graphicx.sty, graphics.sty)を読み込む。
  • 「graphicx + color共用のdvipdfmx用ドライバ」のファイル(dvipdfmx.def)を読み込む。
  • colorパッケージのプログラムのファイル(color.sty)を読み込む。
  • 「graphicx + color共用のdvips用ドライバ」のファイル(dvips.def)を読み込む。
  • その結果、graphicxのドライバ依存コードもdvips用のもので上書きされてしまうので、graphicxパッケージがあたかも dvips オプションを指定した時のような動作をする。これはdvipdfmxを用いている場合は不正な出力になる。
  • 一方、colorはdvips用ドライバでも(表面上は)問題なく動作する。

もちろん、元々が「不正なコード」であるのでその動作は「未定義」であり何が起こっても文句は言えないのだが、実際にこの現象が起きてしまうとその原因を突き止めるのは困難である。

普段から、パッケージのドライバ指定に十分気を付けることを心掛けたい。