TeXLive 2013のmf2pt1がおかしい件


概要

色々な理由から、METAFONTで記述されたフォントを改造することになった。しかし、普通のMETAFONTはビットマップフォントしか生成出来ない。そこで、MetaPostなどを利用してなんとかAdobe Type1形式のフォントを得ようと試みていた最中に事件が発生した。

ヤバいEnglishしか書けなかったが、全然解決する見込みがないのでStackExchangeに投げたものを公開する。
http://tex.stackexchange.com/questions/122644/wrong-tfm-generated-by-mf2pt1-in-texlive-2013
This post, written in poor English, is the nearly same as this article.

やったこと

とりあえず、事件が発生するに至った手順を記述する。

元となるMETAFONTファイルの用意

METAFONTで記述されたフォントは、人間でも読める形になっている。例えばTeXで皆がよく利用する cmr10 (Computer Modern Roman 10)の冒頭は次のように記述されている。

% THIS IS THE OFFICIAL COMPUTER MODERN SOURCE FILE cmr10.mf BY D E KNUTH.
% IT MUST NOT BE MODIFIED IN ANY WAY UNLESS THE FILE NAME IS CHANGED!

% Computer Modern Roman 10 point
if unknown cmbase: input cmbase fi

font_identifier:="CMR"; font_size 10pt#;

u#:=20/36pt#;      % unit width
width_adj#:=0pt#;    % width adjustment for certain characters
serif_fit#:=0pt#;    % extra sidebar near lowercase serifs
... 省略 ...

このファイル(cmr10.mf)を例に今後の話を進めてゆく。

コンパイル

METAFONTファイルをそのままTeXに流し込むことなど出来ないので、TeXが読める物体へコンパイルする必要がある。ここでmfというMETAFONTのコンパイラを使うという選択肢もあるが、これではビットマップフォントしか生成出来ない。そこで、mf2pt1という物を使ってAdobe Type 1(Type 1 font)へコンパイルすることにした。
この作業にあたっては東京大学大学院人文社会系研究科/文学部西洋古典学研究室の学生有志によるWikiページから多くの知識を得た。

このmf2pt1は、

  1. METAFONTファイルから一文字ずつフォント情報をMetaPostでEPS形式に変換
  2. 一文字ずつに生成されたEPSファイルをマージ(マージされたファイルを “disassembled” Type 1 font と呼ぶらしい)
  3. disassembled Type 1 fontをt1asmt1utilsに収録)でバイナリ形式のType 1 fontに変換
  4. fontforgeでレンダリングヒント(カーニング情報などか?)を適用

という手順を踏むらしい。

例えば cmr10.mf をコンパイルすると、最終的に次の成果物が得られる。

  • PFBファイル(Adobe Type 1フォント)
  • TFMファイル(TeX Font Metricファイル)
  • AFMファイル(Adobe Font Metricsファイル)

今回はTFMファイルで事件が起きた。

TFMファイル

そもそもTFMファイルとは、あるフォントについて、文字のカーニングやリガチャの情報を持つファイルのこと。例えばTeXで ffi という文字を表示させると次のようになる。

明らかに fi が融合していると分かる。
また、 Wr という文字を表示させると次のようになる。

この例では W の右側に r が食い込んでいるように見える。

このように、TFMファイルに記述された情報によってTeXは文字と文字の幅などを調整している。つまりTeXであるフォントを使うこととなった場合は、Adobe Type 1形式などのフォントファイルに加えて、TFMファイルなどのフォントのカーニングといった情報を持つファイルも同時に必要となる。

TFMファイルの閲覧

TFMファイルはバイナリファイルなので、そのままでは何が書かれているのか分からない。そこでtftoplで人間が読める形に変換出来る。
例えばTeXLive 2013で配布されているcmr10.mfについて、tftoplを使うと次のような出力が得られる。

(FAMILY CMR)
(FACE O 352)
(CODINGSCHEME TEX TEXT)
(DESIGNSIZE R 10.0)
(COMMENT DESIGNSIZE IS IN POINTS)
(COMMENT OTHER SIZES ARE MULTIPLES OF DESIGNSIZE)
... 省略 ...

事件

端的に言えばmf2pt1で得られたTFMファイルが壊れていた。mf2pt1cmr10.mfをコンパイルして得られたTFMファイルの一部が次のようになっている。

   (LABEL C f)
   (LIG C i O 14)
   (LIG C f O 13)
   (LIG C l O 15)
   (KRN O 47 R 0.004861)
   (KRN O 77 R 0.004861)
   (KRN O 41 R 0.004861)
   (KRN O 51 R 0.004861)
   (KRN O 135 R 0.004861)

これは文字 f に関するリガチャとカーニングの設定の一部である。LIGがリガチャに関する情報を表わし、KRNがカーニングに関する情報を表わす。
なんとなく上手くいっているように見えるが、TeXLiveで配布されているcmr10.tmfから同じく f に関する情報を抜き出してくると、

   (LABEL C f)
   (LIG C i O 14)
   (LIG C f O 13)
   (LIG C l O 15)
   (KRN O 47 R 0.077779)
   (KRN O 77 R 0.077779)
   (KRN O 41 R 0.077779)
   (KRN O 51 R 0.077779)
   (KRN O 135 R 0.077779)

などと、カーニングが相当違う値になっている。

原因

なんとか上手く動くようにならないものかと思い、色々やってみた。すると、 TeXLive 2012 であるとmf2pt1で(恐らく)妥当なTFMファイルが得られるということが分かった。また、mf2pt1はPerlで書かれたスクリプトなので中身を読んでみたところ、中でMetaPostを用いてそれでTFMファイルを生成しているということも分った。さらに、TeXLive 2012から2013でMetaPostのバージョンが1.504から1.803へアップデートしているというのも分かった。

例えばcmr10.mfmf2pt1でコンパイルした場合、

$ mpost -mem=mf2pt1 -progname=mpost '\mode:=localfont; mag:=100.375; bpppix 0.02; nonstopmode; input cmr10.mf'

というコマンドが走るということが分かった。なので、このコマンドをTeXLive 2012(MetaPost 1.5)とTeXLive 2013(MetaPost 1.8)で実行したところ、TeXLive 2013では異常なTFMファイルが生成された。

このあたりのことから、恐らく次のような問題だと思われる。

  • MetaPostにバグがある
  • mf2pt1が古い命令を使っていて、それがMetaPost 1.8では正しく動作しない

ただ、MetaPostなど全く触ったことがなかったので、これ以上の原因究明は出来なかった。とりあえずmf2pt1をガシガシ使っている人は、TeXLive 2013へのアップデートをしばらく見送ってもいいのではないかと思う。

mfplain

mf2pt1.mfの中味を見てみると、次のように、

input mfplain;

mfplainという謎の物体を呼び出しているということが分かった。このmfplainMetaPostのマニュアルの「Legacy Information -> MetaPost Versus METAFONT」で次のように記述されている。

Since METAFONT is intended for making TEX fonts, it has a number of primitives for generating the tfm files that TEX needs for character dimensions, spacing information, ligatures and kerning. MetaPost can also be used for generating fonts, and it also has METAFONT’s primitives for making tfm files.

どうやら、MetaPostにはTFMファイルを生成するためのプリミティブが用意されているらしい。さらに、

Even though MetaPost has the primitives for generating fonts, many of the font-making primitives and internal variables that are part of Plain METAFONT are not defined in Plain MetaPost. Instead, there is a separate macro package called mfplain that defines the macros required to allow MetaPost to process Knuth’s Computer Modern fonts ...

とあるので、METAFONTにはあるけどMetaPostのプリミティブではないような命令を、mfplainでマクロとして定義しているらしい。
ということはこのmfplainがTeXLive 2012と2013で異なっていれば、犯人はこのmfplainという可能性が高まる。そこでmfplainのバージョンをそれぞれのTeXLiveで調べてみた。
しかし、両方ともバージョン1.9でdiffは取ってないが恐らくは同じ物体であると思われる。

ちなみにMetaPostのTFMファイル生成用プリミティブは、先ほどのマニュアルによると、

making_tfm_primitives

となっているらしい。今回はカーニングに関する情報が破損したわけだが、なんだかそのままズバリっぽいkernというプリミティブがある。

ゆえに、

  • mfplainmf2pt1.mpが原因である可能性は少ない
  • MetaPostのTFMファイル生成用のプリミティブが犯人である可能性が高い

と言えるような気がする。ということで、MetaPostのchange logを見てみたものの、プリミティブの仕様が変わったというような情報は多分ないように見える。
これは迷宮入りしそう……。

回避法

具体的な原因は分からないが、とりあえず現時点でなんとかマトモと思われるTFMファイルを生成する方法をいくつか書いておく。

  • TeXLive 2012のmf2pt1を使う(MetaPost 1.5を使う)
  • mfコマンドでMETAFONTファイルからTFMファイルを生成する
  • afm2tfmを用いてAFMファイルからTFMファイルを生成する

このあたりがよいのではないかと思う。
もしかしたら、TFMファイルの代替としてAFMファイルを使うことが出来るのかもしれないが、どうすれば出来るのかは分からない。