dvi-format

# DVI format

May, 2021

       目 次

    1. DVIファイルのフォーマット
         プリアンブル
         ページ数の個数のページ記述部
         ポストアンブル
    2. フォントの定義とDVIware
    3. DVI命令
         DVI命令一覧
    4. pTeX における縦書きと横書きの切替
    5. DVIファイルと可読テキスト形式ファイルとの間の変換
         例

関連リンク
dvioutのインストール
TFMファイルとJFMファイル

## 1. DVIファイルのフォーマット

- DVIファイルは，1 byte のDVI命令と，それに続く 0 byte以上の引数の繰り返しから成り立っています．
- 引数は，整数や文字列などのデータからなります．
- 引数の各整数は，1 byte, 2 byte, 3 byte, 4 byte のいずれかで記述され，符号付きのものと符号無しのものがあります．
  最初の byte が最高位の bits を表し，最後の byte が最下位の bits を表します．
  符号付きの場合，符号は最初の byte の最高位の bit に対応します．
- 位置などを表す数は基本的にすべて 4 byte 整数を用いて十分な精度で表現されます． 位置調整などの長さは小さな数になることが多いので，DVIファイルには 4 byte 以下の整数も導入することによって，DVIファイルのサイズを小さくする工夫がなされています．
- TeXでは，数として小数は用いず，整数とその間の計算のみが用いられます．従って，誤差の違いのため処理系で結果が異なる，というようなことは生じません．
- DVIファイルは，ファイルの先頭が プリアンブル で，その後 ページ記述部 となり，最後に ポストアンブル があります．ページ記述部は各頁毎に分かれて独立した形になっています．

###

###

###

    プリアンブル
         pre(247) で始まり，寸法の単位や，DVIを作成したTeXのコメント文がある(例)
      pre i[1] num[4] den[4] mag[4] k[1] x[k]    (15+k) byte
             i[i]    DVIのバージョン番号で現在 2
             num[4]  スケールファクター（32bit符号無し整数）  通常  25400000
             den[4]  デザインサイズ（32bit符号無し整数）      通常 473628672 = 7227x216
                     DVIファイルにおける寸法の単位を，num/den x 10-7 m にする
                     通常 1 sp（scaled point) = 2-16 pt = 1.525...x10-5 pt = 5.362...x10-9 m = 0.0000053..mm
                     232 (=4294967296) sp = 23.03...m
                     1 inch = 2.54cm  = 72.27 pt
             mag[4]  拡大率（32bit符号無し整数）
                     上記で決めた寸法を mag/1000 倍して使用
                     拡大縮小を行わないときは，mag = 1000
             k[1]    コメント文の長さ（0 - 255）
             x[k]    コメント文

    ページ数の個数のページ記述部
        最初のページ（例）
          bop(149) で始まるヘッダ
      bop c0[4] c1[4] c2[4] c3[4] c4[4] c5[4] c6[4] c7[4] c8[4] c9[4] p[4] (45 byte)
    　　　   c0[4],... TeX において \shipout が実行されたときの \cout0,... の値のコピー
                    c0 は，TeXにおける頁番号．c1,...,c9 は通常 0
             p[4]   直前のページのbopの位置
                    最初のページでは，NULLポインタを表す -1 の値が入っている

          ページの内容の記述
      移動命令，フォント定義命令，文字や箱の描画命令など

          eop(140) ページの終わり
      eop (1 byte)

        次のページ（最初のページと同様）
          bop(149) で始まるヘッダ
      bop c0[4] c1[4] c2[4] c3[4] c4[4] c5[4] c6[4] c7[4] c8[4] c9[4] p[4] (45 byte)

          ページの内容の記述
      移動命令，フォント定義命令，文字や箱の描画命令など

          eop(140) ページの終わり
      eop (1 byte)

      ...

        最後のページ
          bop(149) 始まるヘッダ
      bop c0[4] c1[4] c2[4] c3[4] c4[4] c5[4] c6[4] c7[4] c8[4] c9[4] p[4] (45 byte)

          ページの内容の記述
      移動命令，フォント定義命令，文字や箱の描画命令など

          eop(140) ページの終わり
      eop (1 byte)

    ポストアンブル
        post(248) で始まるヘッダ（例）
      post p[4] num[4] den[4] mag[4] l[4] u[4] s[2] t[2] (29 byte)
             p[4]    最後のページの bop の位置
             num[4], den[4], mag[4]  preamble におけるのと同じ値
             l[4]    ページにおける高さと深さの最大値の和
             u[4]    ページの幅の最大値
             s[2]    スタックの最大レベル
             t[2]    全ページ数（すなわち，bop命令の数）

        フォント定義命令（これがフォントの数だけ並ぶ）
            fntdef1(243), fntdef2(244), fntdef3(245), fntdef4(246) のいずれかで始まるフォント定義
      fntdefx k[x] c[4] s[4] d[4] a[1] l[1] n[a+l] (15+x+a+l byte）
             k[x]    フォント番号
             c[4]    フォント(TFMファイル）のチェックサム
             s[4]    スケールファクター
             d[4]    デザインサイズ
             a[1]    フォントのディレクトリ名の部分の長さ（通常 0）
             l[1]    フォントの名前の部分の長さ
             n[a+l]  フォント名の文字列

        ...

        フォント定義命令
      fntdefx k[x] c[4] s[4] d[4] a[1] l[1] n[a+l]

        post_post(249) で始まる末尾
      post_post q[4] i[1] 223,...,223 (10 - 13 byte)
             q[4]    post の位置
             i[1]    フォーマットの ID（通常 2 だが，pTeX の縦書きでは 3）
             223 ... 223  DVIファイルサイズが 4 の倍数となるよう 4 - 7個の 223 を置く

## 2. フォントの定義とDVIware

- フォントの選択はフォントの番号でなされますが，番号と実際のフォントとの対応がフォントの定義です．この対応は，全頁を通して同じものでなければなりません．
- 各ページ記述部には，そのページで使われるフォントの定義が含まれています．
- ポストアンブルの部分に，そのDVIファイルで用いられた全てのフォントの定義のリストがあります． DVIwareは，ポストアンブルを読むだけで，そのDVIファイルで使われているフォントの情報を得ることができます．
- TeX で通常使われているフォントの番号は，0 から 255 までです．

DVIファイルを読んで表示・印刷などを行う DVIware は，次のようにしてDVIファイルを解釈することができます．

1. DVIファイルの先頭の 1 byte が pre で，その次の 1 byte が 2 でないと通常のDVIファイルとは認められない．
2. DVIファイルを，末尾からさかのぼって 223 以外の値を得るまで，バイト単位で読みます．
3. 223 の個数が 4個から 7個までの間でないと不正
4. 上記の 223 以外の値が 2 なら通常の DVI ファイル，3 なら縦書きを含む pTeX，それ以外ならばエラー
5. そこから前の 4 byte を読んで q[4] すなわち post の位置を得る．
6. その位置の 1 byte が post でなければエラー
7. post の次からの 28 byte を読んで p[4] num[4] den[4] mag[4] l[4] u[4] s[2] t[2] を得る．
   ・ num den mag から，DVIファイルでの長さの単位と拡大率を得る．
   ・ s からスタックのために確保すべき領域サイズを得る（4 x 6 x s byte）．
   ・ t は総ページ数
   ・ p は最後のページの bop の位置
8. post の 29 byte 後からはフォント定義命令が続いているので，フォント定義命令が終了するまで（すなわち post_post まで）読んで，DVIファイルで使われる全フォントの情報を得る．
9. 各ページの bop から数えて 41 byte からの 4 byte の p[4] は，その前のページの bop の位置であるので，最終ページから逆にたどることによって，各ページの bop の位置が分かる．
   ・ 実際に bop が存在すること，最初のページに書かれた p[4] が -1 であることをチェックしておく．
   ・ bop の次の 4 byte c0[4] は TeX におけるページ番号として用いられているので，利用できる．
10. 必要なページを，そのページの bop の 45 byte 後から順に，ページの終わりの eop に出会うまで，解釈する（DVI命令を翻訳して出力する）．

## 3. DVI命令

変数 | 役割
--- | ---
h | カレントポイントの水平位置
v | カレントポイントの垂直位置
w | 水平移動量の変数
x
y | 垂直移動量の変数
z
f | カレントフォント

1つのページ記述部は，bop 命令で始まり，eop 命令で終わります．

そこでは右の7つの変数 h, v, w, x, x, y, z, f が使用されますが，それらは f を除いて各ページの始まりで 0 に初期化されます．ただし，f のみは未定義，となります．

座標の原点は，用紙の左上端から右へ 1 inch， 下へ 1 inch の用紙内部にあり，座標 (h,v) の点とは，そこから右へ h，下へ v の位置の点を表します．

描画は，常にカレントポイント (h,v) という座標の点を基準になされ， 「高さ a，幅 b の箱の描画」とは， 「カレントポイントが箱の左下端となるような中の詰まった箱の描画」を表します． 例えば罫線は，その太さを高さに，長さを幅に設定して描画されます．

以下に，DVI命令の一覧を載せます．そこでは，

- 番号 f のフォントに属するコード番号が xx の文字を，ch(f,xx) と表しています．
- この文字 ch(f,xx) の幅を w(f, xx) と表しています．
- 以下の，setcharxx，setrule，putrule，fntnumyy, fntdefx は，通常それぞれ，set_char_xx
，set_rule，put_rule，fnt_num_yy，fnt_def_x と表記されます．
- 文字幅 w(f, xx) の情報は TFMファイル（フォントメトリックファイル）に書かれていて，DVIファイルには書かれていません．従って，DVIファイルを解釈して実際に印刷をする場合には TFM ファイルなどから，この文字幅の情報を得る必要があります．

  > この文字幅情報は，文字の画像データが入っている PKフォントファイルや，バーチャルフォントファイルにも TFM ファイルからコピーされて入っていますので，DVIware は，文字幅情報をこれらのファイルから得ることもできます．

DVI命令一覧

コード 命令 引数[符号付bytes] 意味
0 setchar0 なし 文字 ch(f,0) を (h,v) に描画，h ← h + w(f,0)
... setcharxx なし 文字 ch(f,xx) を (h,v) に描画，h ← h + w(f,xx)
127 setchar127 なし 文字 ch(f,127) を (h,v) に描画，h ← h + w(f,127)
128 set1 c[1] 文字 ch(f,c) を (h,v) に描画，h ← h + w(f,c)
129 set2 c[2]
130 set3 c[3]
131 set4 c[4]
132 setrule a[4] b[4] 高さ a，幅 b で箱を (h,v) に描画，h ← h+b
133 put1 c[1] 文字 ch(f,c) を (h,v) に描画
134 put2 c[2]
135 put3 c[3]
136 put4 c[4]
137 putrule a[4] b[4] 高さ a，幅 b で箱を (h,v) に描画
138 nop なし 何もしない
139 bop c0[4] ... c9[4] p[4] ページの始まり，(h,v,w,x,y) ← 0，スタックを空に
140 eop なし ページの終わり
141 push なし (h,v,w,x,y,z) をスタックに待避
142 pop なし (h,v,w,x,y,z) をスタックから戻す
143 right1 b[1] h ← h+b
144 right2 b[2]
145 right3 b[3]
146 right4 b[4]
147 w0 なし h ← h+w
148 w1 b[1] h ← h+b，w ← b
149 w2 b[2]
150 w3 b[3]
151 w4 b[4]
152 x0 なし h ← h+x
153 x1 b[1] h ← h+b, x ← b
154 x2 b[2]
155 x3 b[3]
156 x4 b[4]
157 down1 a[1] v ← v+a
158 down2 a[2]
159 down3 a[3]
160 down4 a[4]
161 y0 なし h ← h+y
162 y1 a[1] h ← h+a，y ← a
163 y2 a[2]
164 y3 a[3]
165 y4 a[4]
166 z0 なし h ← h+z
167 z1 a[1] h ← h+a，z ← a
168 z2 a[2]
169 z3 a[3]
170 z4 a[4]
171 fntnum0 なし f ← 0
... fntnumyy なし f ← yy
234 fntnum63 なし f ← 63
235 fnt1 k[1] f ← k
236 fnt2 k[2]
237 fnt3 k[3]
238 fnt4 k[4]
239 xxx1 k[1] x[k] special の文字列 x，意味は任意
240 xxx2 k[2] x[k]
241 xxx3 k[3] x[k]
242 xxx4 k[4] x[k]
243 fntdef1 k[1] c[4] s[4] d[4] a[1] l[1] n[a+l] フォント k の定義
244 fntdef2 k[2] c[4] s[4] d[4] a[1] l[1] n[a+l] フォント k の定義
245 fntdef3 k[3] c[4] s[4] d[4] a[1] l[1] n[a+l] フォント k の定義
246 fntdef4 k[4] c[4] s[4] d[4] a[1] l[1] n[a+l] フォント k の定義
247 pre i[1] num[4] den[4] mag[4] k[1] x[k] プリアンブル始まり
248 post p[4] num[4] den[4] mag[4] l[4] u[4] s[2] t[2] ポストアンブル始まり
249 post_post q[4] i[1] 223 ... 223 ポストアンブル終わり
250 opcode - 未定義
... opcode -
254 opcode -
255 dir o[1] 横書き／縦書き切替（pTeX），元来は未定義

## 4. pTeX における縦書きと横書きの切替

- dir(255) 命令は，ASCII の pTeX で縦書きを記述するために使われ
  o[1] = 0 : 横書き
  1 : 縦書き
  という切替を表します．
- 縦書きへの切替で，カレントポイントを基準に紙面を反時計回りに90度回転させて，以降の移動や描画を行います．
- 縦書き用の和文の文字は，和文の（縦書き）文字を反時計回りに90度回転して定義されているので，縦書きでも，横書きと同じように文字や箱を描画し，印刷後に紙面を90度回転してもとに戻せば，通常の縦書きの和文の文書となります．
- 縦書きでは，紙面を元に戻すと h の正の方向は下を，v の正の方向は左を表します． 横書きも含めて，h は行の中で進む方向を，v は行送りの方向を表すことになります．
- 縦書きから横書きへの切替では，カレントポイントを基準に時計回りに紙面を90度回転させて元来の向きに戻します．

## 5. DVIファイルと可読テキスト形式ファイルとの間の変換

- TeX のパッケージに dvitools として付属しているものに，dvitype および pTeX にも対応した pdvitype があり，これは DVIファイルを可読形式に変換します．
  - これはカレントポイントの実際の移動量や文字の描写位置を表示するため，TFM（フォントメトリック）ファイルを読みます．これの出力した形式のテキストファイルをDVIファイルに変換するプログラムが存在するかどうかは知りません（フォントのチェックサム情報などが出力されないので，出力結果のみからの復元は無理）．
- DVIファイルと可読テキストファイル（DTL:DVI Text Language）との相互変換を行うプログラム dv2dt/dt2dv が存在します．pTeX には対応していません．
- dviout のパッケージ(Ver.3.15以降）には，dvispc というプログラムが付属していて，これは pTeX も含め DVIファイルと可読テキストファイルの相互変換をサポートしています．

### dvispc

- dv2dt/dt2dv より読みやすいテキスト形式（3. DVI命令 で述べた形 --- pdvitype などと同じ --- に対応，さらに意味を示すコメントも付加可能）が用いられていますが，dv2dt/dt2dv の可読テキスト形式での入出力もでき，dv2dt/dt2dv よりも高速です．

- ソースをコンパイルすれば，Unix 等でも使用可能です．

- 応用として，たとえば以下のようにすれば foo.dvi の 1ページ目と20ページ以降を抜き出した foo2.dvi が作成されます．

         dvispc -atpT3/20-L foo.dvi | dvispc -x foo2.dvi

  ここで，-a: DVI → Text変換 -t: DTL形式（出力サイズが小さくなる） -pT3/20-L: 出力箇所の指定で，T はプリアンブル，3 20- は 3ページ目，20ページ目以降，L はポストアンブルを，それぞれ表し，-x: は TeX → DVI変換 の指定を表す．

  awk スクリプトなどのフィルターを間に挟むと，様々な加工が可能です． 例えば，foo.dvi の special を全て削除した foo2.dvi は以下のように作成できます．

         dvispc -aj foo.dvi | grep -v ^xxx | dvispc -x foo2.dvi

- 以下に -avl というパラメータでの TeX → DVI変換 の一部を載せます（dviout のパッケージに付属の epsfdoc.dvi を用いた例）．

      プリアンブル
      0: pre 2/id 25400000/num 473628672/den 1000/mag 27/len ' TeX output 2000.02.21:0054'

      上に引き続く最初のページ
       [1]
      42: bop 1/page 0 0 0 0 0 0 0 0 0 -1/former_bop
      87: down4 46202880
      92: push
      93: down4 -45613056
      98: push
      99: push
      100: right3 1114112
      104: xxx1 17/len 'color push  Black'
      123: right4 27394048
      128: xxx1 9/len 'color pop'
      139: pop
      140: pop
      141: down4 43646976
      146: push
      147: down4 -38549854
      152: push
      153: push
      154: push
      155: right4 9009997
      160: xxx1 17/len 'color push  Black'
      179: xxx1 9/len 'color pop'
      190: pop
      191: pop
      192: right4 9337677
      197: fntdef1 33 0x44D3ED74/c-sum 1132462/s-size 1132462/d-size 0/dir 5/name 'cmr17'
      218: fntnum33
      219: setchar68
       "D"
      220: right2 -29583
      223: setchar86
      224: setchar73
      225: setchar79
      226: setchar85
      227: setchar84
       "VIOUT"
      ...
      465: fntdef1 49 0xE99FD0F6/c-sum 943718/s-size 655360/d-size 0/dir 6/name 'goth10'
      487: fntnum49
      488: set2 0x244f "は"
      491: set2 0x2438 "じ"
      494: set2 0x2461 "め"
      497: set2 0x244b "に"
      500: pop
      501: z3 1474560
      ...
      5200: eop        最初のページ終わり

      2ページ目
       [2]
      5201: bop 2/page 0 0 0 0 0 0 0 0 0 42/former_bop
      ...

      ...
      26001: eop       7ページ目の終わり

      8ページ目（最後のページ）
       [8]
      26002: bop 8/page 0 0 0 0 0 0 0 0 0 21404/former_bop
      ...
      26786: pop
      26787: right4 27394048
      26792: xxx1 9/len 'color pop'
      26803: pop
      26804: pop
      26805: eop       最後のページ終わり

      ポストアンブル
      26806: post 26002/final_bop 25400000/num 473628672/den 1000/mag 46202880/h+d 28508160/w 13/stack 8/pages
      26835: fntdef1 54 0xC2D64EA0/c-sum 786432/s-size 786432/d-size 0/dir 6/name 'cmbx12'
      26857: fntdef1 53 0xDFEA3C78/c-sum 655360/s-size 655360/d-size 0/dir 6/name 'cmtt10'
      26879: fntdef1 51 0xC2D64EA0/c-sum 943718/s-size 786432/d-size 0/dir 6/name 'cmbx12'
      26901: fntdef1 49 0xE99FD0F6/c-sum 943718/s-size 655360/d-size 0/dir 6/name 'goth10'
      ...
      27196: fntdef1 7 0x4BF16079/c-sum 655360/s-size 655360/d-size 0/dir 5/name 'cmr10'
      27217: fntdef1 6 0xD993A052/c-sum 458752/s-size 458752/d-size 0/dir 4/name 'cmr7'
      27237: post_post 26806/post 2/id 223 223 223 223 223            DVIファイルの終わり

  誤りや補足すべき点があればお知らせ下さい --> dviout@tug.org