マクロツイーター

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

「最小のDVI」を吐かせる話(1)

例のクイズの話。

まずは LaTeX で適当に試してみる

当然であるが、ページ上に何か文字を書くと、当然それを記録するために DVI ファイルの大きさは増えるはずである。だから最小の DVI ファイルは「白紙」であるはずである。そこで本文が空の LaTeX 文書を作ってみる。

\documentclass{article}
\begin{document}\end{document}% 本体が空

これを quiz.tex として latexコンパイルすると……。

No pages of output.
Transcript written on quiz.log.

これではそもそも DVI が出力されず問題の条件を満たさない。なので、取りあえず、空の箱を置いてみる。

\documentclass{article}
\begin{document}\mbox{}\end{document}% 空の箱を置く
Output written on quiz.dvi (1 page, 208 bytes).
Transcript written on quiz.log.

残念ながら 208 バイトもの巨大な DVI ファイルができてしまった。実はこの DVI ファイルは「白紙」ではない。実際に表示させてみると、紙面下部に「1」というノンブルがしっかりと出力されている。というわけで、これを消してみる。

\documentclass{article}\pagestyle{empty}% ノンブル無し
\begin{document}\mbox{}\end{document}
Output written on quiz.dvi (1 page, 152 bytes).
Transcript written on quiz.log.

56 バイトもの大幅なサイズ削減に成功した。しかしもっと減らせないだろうか。

plain TeX で試してみる

何となく LaTeX よりも plain TeX の方が“単純”で自由度が高そうがから、ここからは plain TeXtex コマンド)で頑張ってみる。

\nopagenumbers % ノンブル無し
\leavevmode\bye % 空の段落を置いて終了
Output written on quiz.dvi (1 page, 152 bytes).
Transcript written on quiz.log.

さっきと同じ結果になった。今度は水平モードに移行せずに垂直モードのまま空の箱を置いてみる。

\nopagenumbers \null \bye
% \null は \hbox{} に展開されるマクロ
Output written on quiz.dvi (1 page, 144 bytes).
Transcript written on quiz.log.

さらに小さくなった。しかし、そもそも「最小」の出力を得たいのであれば、それが何バイトであるのかを知る必要があるだろう。

最小の DVI ファイルとは何か

これを調べるため、DVI の中身を“解読”するツール dv2dt を利用してみる。*1直近の quiz.dvi(144 バイト)に対して

dv2dt quiz.dvi quiz.dtl

を実行すると、次のような“ダンプファイル”(DTL形式)quiz.dtl が得られる。(# 以降のコメントは私が補足したもの。)

variety sequences-6                                            # dv2dtの出力形式(DTL)のヘッダ
pre 2 25400000 473628672 1000 27 ' TeX output 2015.05.22:2222' # DVIのプレアンブル部
bop 1 0 0 0 0 0 0 0 0 0 -1                                     # ページ開始
[                                                              #   以下ページ記述命令が並ぶ
d3 -917504
]
d4 42152922
d3 1572864
eop                                                            # ページ終了
post 42 25400000 473628672 1000 43725786 30785863 2 1          # DVIのポストアンブル部開始
post_post 103 2 223 223 223 223 223 223                        # DVIのポストアンブル部終了

なお、DVI の書式についての情報は CTAN に dvistd パッケージとして公開されている。(日本語の資料としてアスキーによる解説がある。)

DVI の仕様に依ると、プレアンブル部(pre)とポストアンブル部(post、post_post*2)は必須の要素である。DVI ファイルは少なくとも一つのページを必ず持っている*3ので、1 組の bop と eop も必須である。従って、現状の quiz.dvi から削減できる要素は次の 2 つに限られる。

  • bop と eop の間にあるページ記述命令群。*4
  • プレアンブル(pre)に含まれる“DVI コメント”の文字列。上記の DTL の中の ' TeX output 2015.05.22:2222' のことである(その前の 27 はバイト数を表す)。

以上のことより、「最小の正常な DVI」は以下のようになるはずである。

variety sequences-6
pre 2 25400000 473628672 1000 0 ''                             # DVIコメントを空文字列にした
bop 1 0 0 0 0 0 0 0 0 0 -1                                     # ページ描画命令列を空にした
eop
post XX 25400000 473628672 1000 43725786 30785863 2 1          # 'XX'はbopのオフセット
post_post YY 2 223...                                          # 'YY'はpostのオフセット

ここで “XX” と “YY” にはファイル中の特定の命令の存在位置(先頭からのオフセット値)を示す整数値が入る。また DVI ファイルの末尾については「ファイルサイズが 4 の倍数になるように 4〜7 個のバイト値 223 の列を置く」という規則がある。これを考慮して上記のものを正常な DTL に書き換えると以下のようになる。((この結果を容易に得るには、dv2dt の逆変換ツールである dt2dv の自動補正機能を利用する。当該のソース中の XXYY0 に変えて、またコメントと「223...」を除去して、“DTL の文法に適う”ファイル quiz.dtl を作り、それを「dt2dv quiz.dtl quiz.dvi」で変換すると、「値が間違っている」という警告メッセージとともに、正しい値に修正された DVI ファイル quiz.dvi が得られる。あとはそれを再び dv2dt で変換すればよい。))

variety sequences-6
pre 2 25400000 473628672 1000 0 ''
bop 1 0 0 0 0 0 0 0 0 0 -1
eop
post 15 25400000 473628672 1000 43725786 30785863 2 1
post_post 61 2 223 223 223 223

そして、これに相当する DVI ファイルは以下の HEX ダンプで表される 100 バイトのファイルである。

00000000  F7 02 01 83 92 C0 1C 3B-00 00 00 00 03 E8 00 8B
00000010  00 00 00 01 00 00 00 00-00 00 00 00 00 00 00 00
00000020  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
00000030  00 00 00 00 00 00 00 00-FF FF FF FF 8C F8 00 00
00000040  00 0F 01 83 92 C0 1C 3B-00 00 00 00 03 E8 02 9B
00000050  33 DA 01 D5 C1 47 00 02-00 01 F9 00 00 00 3D 02
00000060  DF DF DF DF                                    

というわけで、目標とすべきは、この 100 バイトの quiz.dvi を TeX エンジンに出力させることである。

(続きはまた後日)

*1:DVI を解読する他のツールとして dvitype や DVIasm 等がある。

*2:なお、post と post_post の間には当該の DVI ファイルが使用するフォントの情報が列挙される。quiz.dvi は文字(フォント)を一切含まないのでこの部分が空になっている。

*3:dvistd 資料の A.1 節: A DVI file consists of a “preamble,” followed by a sequence of one or more “pages,” followed by a “postamble.”

*4:現状では、参照点の移動だけを行っていて結局何も出力していない。