DVI 変換(dvipdfmx / dvips / ptex2pdf)

latex と打ったのに PDF が出てこない——これは故障ではありません。LaTeX のいちばん古いコマンドは PDF ではなく DVI を書き、そこから先は dvipdfmxdvipsdvisvgm という DVI 変換器 の仕事だからです。DVI という形式そのものは、Knuth の DVItype のソースによれば 1979 年に David Fuchs が最初のプログラムを書いた時代までさかのぼります。PDF が生まれるより十数年前です。それでも pdflatex が主流になった今日、この二段構えが消えないのには理由があります。このページでは、TeX Live 2024 に入っている変換器がそれぞれ何を食べて何を出すのか、日本語の uplatexdvipdfmx 経路がなぜ今も定石なのか、そして変換の段で出るエラーの読み方を扱います。

なぜ DVI を経由するのか——pdflatex があるのに残っている理由

DVI(device independent)は「何ページ目の、この座標に、このフォントのこの文字を置く」という指示だけを並べた中間形式です。フォントの実体は入っておらず、色も画像も持ちません。この身軽さが要点で、TeX 本体は組版だけに集中し、紙に何をどう載せるかという機器側の事情は変換器に丸投げできる——1979 年の設計判断が、そのまま今日の PostScript・PDF・SVG への出口になっています。つまり DVI が残っているのは互換性のためだけではありません。pdflatex は PDF しか書けませんが、DVI があれば同じ組版結果を PDF・PostScript・SVG の三方向へ分岐できます。加えて、PSTricks 系のパッケージは PostScript のインタプリタを前提にした \special で動くので、経路のどこかにインタプリタが要ります。latexdvips はそれを直接与える道です。日本語の pTeX 系エンジンにいたっては、そもそも PDF を直接書く実装が存在しません。

dvipdfmxxdvipdfmxextractbb は同じ一本のプログラム

TeX Live 2024 の bin ディレクトリを覗くと、dvipdfmxdvipdfmextractbbebb の四つがすべて xdvipdfmx への symlink になっています。つまり 五つの名前で一本の実行ファイル で、プログラムは自分がどの名前で呼ばれたかを見て振る舞いを変えます。dvipdfmx --version は「This is dvipdfmx Version 20240305」と名乗り、xdvipdfmx --version は同じ日付で「This is xdvipdfmx」と名乗る——中身は同一です。この事実がわかると、XeTeX 周辺の話も一気に整理されます。xelatex -no-pdf は PDF ではなく .xdv(拡張 DVI)を書き、それを xdvipdfmx が PDF にします。同じバイナリなので dvipdfmx sample.xdv と打っても通ります。祖先の dvipdfm は Mark A. Wicks の作で、CJK 対応・フォント埋め込み・オブジェクトストリームを足して dvipdfmx にしたのは Jin-Hwan Cho と平田俊作らです。

terminal
ls -l $(dirname $(which dvipdfmx))/dvipdfmx
# dvipdfmx -> xdvipdfmx

dvipdfmx sample.dvi            # sample.dvi -> sample.pdf
dvipdfmx -p a4 -o out.pdf sample.dvi
xelatex -no-pdf paper.tex      # writes paper.xdv, not paper.pdf
xdvipdfmx paper.xdv            # paper.xdv -> paper.pdf
オプション働き(TeX Live 2024 の既定値)
-o FILE出力ファイル名。- で標準出力。既定は入力名の拡張子を .pdf に替えたもの
-p a4用紙サイズを名前で指定。既定は a4。一覧は dvipdfmx --showpaper
-V 5PDF のバージョン。既定は 5、すなわち PDF 1.5。投稿先が 1.4 を要求するなら -V 4
-s 1-3,5処理するページ範囲を限定する。カンマ区切りで複数指定できる
-l横向き。用紙の縦横を入れ替える
-z 9zlib の圧縮レベル 0〜9。既定は 9。-z 0 は中身を読みたいデバッグ時に
-f FILE.mapフォントマップを追加で読み込む。埋め込むフォントを差し替えたいときに使う

! LaTeX Error: Cannot determine size of graphic が出たら——ドライバ指定を疑う

DVI 経路で図を入れると、多くの人が最初にこのエラーに当たります。! LaTeX Error: Cannot determine size of graphic in fig.pdf (no BoundingBox). ——原因は画像ファイルではなく、graphicx がどのドライバ向けに動いているかです。TeX Live 2024 の graphics.cfg は、DVI を書く実行では既定で dvips.def を選びます。dvips は PostScript しか埋め込めないので、PDF や PNG のサイズを読む機能を持っていません。プリアンブルで \usepackage[dvipdfmx]{graphicx} と明示すれば、この環境では PDF も PNG も追加ファイルなしでそのまま通ります。 手元で確かめると、.xbb を一切作らず、シェルエスケープも使わずに latex が図を取り込み、dvipdfmx が PDF に埋め込みました。それでも寸法が取れない古い画像には extractbb fig.pdf を走らせます。生成される .xbb%%BoundingBox: 0 0 612 792 のような数行のテキストで、先ほどの symlink のとおり中身は dvipdfmx 自身です。

latex
% name the driver explicitly on the DVI route
\documentclass{article}
\usepackage[dvipdfmx]{graphicx}
\begin{document}
\includegraphics[width=3cm]{fig.pdf}
\end{document}

dvips — PostScript にしかできないことのために残る道

dvips -o paper.ps paper.dvi は DVI を PostScript にします。作者は Tomas Rokicki ですが、man ページの著者欄には「extended to virtual fonts by Don Knuth」とあり、仮想フォント対応を足したのは Knuth 本人、探索パスと設定まわりは Karl Berry という共作です。いま dvips を使う理由は三つに絞られます。PSTricks のように PostScript の演算に依存する図、印刷所が .ps を要求する入稿、そして dvips -E による EPS の切り出しです。-E は本文の内容にぴったり合った BoundingBox(手元の例では %%BoundingBox: 148 88 326 668)を付けた単一図版を書き出します。PDF が欲しければ Ghostscript 同梱の ps2pdf に通すのが定石です。

terminal
dvips -t a4 -o paper.ps paper.dvi   # DVI -> PostScript
ps2pdf paper.ps                     # PostScript -> PDF (Ghostscript)
dvips -E -o figure.eps figure.dvi   # one tightly cropped EPS
オプション働き
-o FILE出力する PostScript のファイル名。省くとプリンタへ送ろうとすることがある
-t a4用紙の種類。a4letterlegal のほか landscape も指定できる
-E1 ページを EPS として書き出す。1 ページ文書専用で、貼り込んだ図の分は BoundingBox に入らない
-P NAMEプリンタ設定 config.NAME を読む。解像度やフォントの扱いが切り替わる
-p 3 -l 73 ページ目から 7 ページ目までを出力する

ここに、知らないと丸一日溶ける落とし穴があります。dvips の経路にビットマップ画像を入れてはいけません。 \includegraphics{dot.png} は、ドライバを dvips にしたままだと先ほどの no BoundingBox で止まりますが、.xbb を手で用意するなどして無理に通すと、今度は LaTeX も dvips も何も言わずに .ps を書き上げます。壊れているのはその先です。手元でその .psps2pdf に流すと Ghostscript が Error: /syntaxerror in (binary token, type=137) を吐き、GPL Ghostscript 10.03.0: Unrecoverable error, exit code 1 で落ちました。PostScript は PNG を知らないので当然なのですが、エラーが最後の最後まで出ないのが厄介なところです。dvips を使うなら図は EPS に統一する。PNG や JPEG や PDF を混ぜたいなら dvipdfmx 経路にする。判断はこの一行で足ります。

dvisvgm — 数式を SVG にする、そしてフォント形式で大きさが変わる

Web に数式を載せるとき、画像にすると拡大でぼやけ、MathML にすると環境ごとに崩れます。dvisvgm(Martin Gieseking、2005 年から開発)は DVI をそのまま SVG に変換するので、ベクタのまま TeX の組版結果が保てます。手元の TeX Live 2024 版は dvisvgm 3.2.2 で、--eps で EPS、--pdf で PDF も入力にできます。ここで効いてくるのが --font-format です。同じ 1 ページを変換したときのファイルサイズを実測すると、既定の SVG 埋め込みフォントで 13,156 バイト、--font-format=woff2 で 8,361 バイト、--no-fonts(グリフをすべてパスに変換)では逆に 23,563 バイトに膨らみました。しかもパス化した SVG には <text> 要素が一つも残らず、検索もコピーもできなくなります。「アウトライン化したほうが軽い」は少なくともここでは成り立ちません。

指定同一ページの実測サイズと性質
(default)13,156 バイト。SVG フォントを埋め込み、<text> 要素は 14 個残る
--font-format=woff28,361 バイト。もっとも小さく、テキストも残る。Web 配信の第一候補
--no-fonts23,563 バイト。すべてパス化され <text> は 0 個。検索もコピーも不可
-z5,383 バイト。gzip 圧縮した .svgz。サーバが対応していれば最小
terminal
latex equation.tex                        # -> equation.dvi
dvisvgm --font-format=woff2 equation.dvi  # -> equation.svg
dvisvgm --pdf figure.pdf                  # PDF input
dvisvgm --libgs=/path/to/libgs.dylib f.dvi  # only if PS specials are used

もう一つ、報告が絶えないメッセージがあります。processing of PostScript specials is disabled (Ghostscript not found) ——Ghostscript は入っているのに、です。手元の環境がまさにそれで、gs/usr/local/bin/gs にあるのに dvisvgm はこう言います。理由は探し方が違うからです。dvisvgm は gs という実行ファイルではなく、libgs という共有ライブラリを実行時に読み込みます。 MacTeX に付いてくる Ghostscript は実行ファイルだけを置いていくので、ライブラリが見つからない。\special を使う図(PSTricks や一部の TikZ 出力)を SVG にしたいなら、共有ライブラリ付きの Ghostscript を入れるか、--libgs= でその場所を教えます。逆に、素の数式や \includegraphics だけの DVI なら、この警告は無視して構いません。

日本語の uplatexdvipdfmx 経路と ptex2pdf

日本語組版で DVI 経路が生き残っているのは、懐古趣味ではなく必然です。pTeX 系のエンジン(ptexeptexuptexuplatex)には PDF を直接書く機能がありません。 縦組み・禁則・和欧文間のアキといった日本語固有の処理は pTeX が持ち、PDF 化と和文フォントの埋め込みは dvipdfmx が引き受ける——という分業で四十年ぶん積み上がってきました。だから手順は必ず二段です。uplatex paper.tex.dvi を作り、dvipdfmx paper.dvi で PDF にします。文書側でも \documentclass[uplatex,dvipdfmx]{jsarticle} のようにドライバを明示しておくと、graphicxcolor が正しい \special を書き出します。

この二段を 1 コマンドにまとめるのが ptex2pdf です。TeX Live 2024 に入っているのは version 20200520.0 で、texjporg(日本語 TeX 開発コミュニティ)と Norbert Preining による texlua スクリプト。実体は texmf-dist/scripts/ptex2pdf/ptex2pdf.lua への symlink で、エンジンを走らせたあと自動で dvipdfmx を呼びます。エンジンはフラグの組み合わせで選び、日本語論文の定番 upLaTeX は -l -u です。細かい指定は -ot で TeX 側へ、-oddvipdfmx 側へ渡します。ただし ptex2pdf はコンパイル回数を数えてくれません。相互参照や文献のある文書では、回数まで面倒を見る latexmk に任せるほうが確実です。

フラグ呼ばれるエンジン
(none)ptex — plain TeX の pTeX 版
-lplatex — pLaTeX。JIS X 0208 の範囲を扱う従来型
-uuptex — 内部 Unicode 版の pTeX
-l -uuplatex — upLaTeX。現在の日本語論文の既定の選択
terminal
# the two steps, written out
uplatex paper.tex          # -> paper.dvi
dvipdfmx paper.dvi         # -> paper.pdf

# the same thing in one command
ptex2pdf -l -u -ot '-kanji=utf8 -synctex=1' paper.tex
ptex2pdf -l -u -s paper.tex   # stop at the DVI

# what to check when the converter fails
dvipdfmx nosuch.dvi
# dvipdfmx:fatal: Could not open specified DVI (or XDV) file: nosuch.dvi
# No output PDF file written.

変換の段で出るエラーと、その意味

メッセージ何が起きているか
dvipdfmx:fatal: Could not open specified DVI.dvi が無い。pdflatex で組んだので DVI が作られていない、というのが最多。終了コードは 1
dvips: DVI file can't be opened同じく入力が見つからない。dvips は名前を省略できないので、拡張子も含めて確認する
dvips: ! Bad DVI file: id byte not 2XeTeX が書いた .xdvdvips に渡している。XDV を読めるのは xdvipdfmx だけ
no BoundingBoxgraphicxdvips 用に動いている。\usepackage[dvipdfmx]{graphicx} を試す
Ghostscript not founddvisvgmlibgs を見つけられない。gs の実行ファイルがあっても別問題

提出前の点検も、経路ごとに見る場所が違います。PDF で出すなら dvipdfmx のあとで、フォントの埋め込み・用紙サイズ・しおり・リンクを実際のビューアで確認します。印刷所へ回すなら dvips.psps2pdf に通す前後で EPS と PostScript の \special が生き残っているかを見ます。エディタからの正順・逆順検索を使うなら、latex -synctex=1 を付ければ DVI 経路でも .synctex.gz が作られます——手元では 860 バイトのファイルができ、dvipdfmx を通してもそのまま残りました。.dvi.pdf.synctex.gz はジョブ名を共有するので、出力先を別ディレクトリにするならビルドツール側で一貫して指定してください。

とはいえ、これらを手で順番に打つ機会は多くありません。latexmk$pdf_mode を切り替えるだけで latexdvipdfmx(u)platexdvipdfmx の経路を面倒みてくれますし、.dvi が古くなったかどうかも判断します。手打ちが要るのは、経路そのものを疑っているとき——つまりこのページの内容が必要になったとき——だけです。逆に言えば、変換器の名前と引数を一度覚えておけば、ビルドツールが何をしているかも読めるようになります。