今さら人に聞けないMETAFONT

>この記事は [TeX & LaTeX Advent Calendar 2015](http://www.adventar.org/calendars/929) の18日目の記事です。
>昨日は [あざらし](http://texmedicine.hatenadiary.jp/entry/2015/12/17/000339) さんでした。明日は [umireon](http://qiita.com/umireon/items/0231594d59f8dce6997b) さんです。

最近METAFONTの素晴らしさに気づきいろいろ勉強していたのですが，METAFONTのライトユーザー向けの日本語文献がほとんど存在しないことに気づき[^1]，せっかくなので備忘録の意味も込めてまとめてみました。

※ 筆者自身の環境は TeXLive2015 (OSX El Capitan) です。従ってWindowsユーザー向けの情報は不十分・不正確な可能性があります。

[^1]: 人に聞けない（物理）

#起動方法
起動できないとお話にならないので，とりあえずは起動方法から。

TeXLiveがインストールされているのであれば，ターミナル（コマンドプロンプト）上で`mf`と入力すればOK。対話環境がスタートします。

~~~bash

$ mf
This is METAFONT, Version 2.7182818 (TeX Live 2015) (preloaded base=mf)
**
~~~

普通の場合であれば，最初の一言でまず`\relax`と入力してから始めましょう[^2]。

~~~bash
$ mf
This is METAFONT, Version 2.7182818 (TeX Live 2015) (preloaded base=mf)
**\relax

*
~~~

あるいは，予め`myfont.mf`などMETAFONTファイルをテキストエディタで作成してから，

~~~bash
$ mf myfont.mf
~~~

として読み込ませたり，

~~~bash
$ mf
This is METAFONT, Version 2.7182818 (TeX Live 2015) (preloaded base=mf)
**\relax

*input myfont;

~~~


として対話モード中にロードすることも可能です。

[^2]: METAFONTの作者もTeX同様Knuthなので，類似したコマンド名も多く存在します。

#エディタ

METAFONTをこの先バリバリ扱っていくわけですから，シンタックスハイライトぐらいには対応したエディタを使いたいものです。ところが残念な（意外な？）ことに，METAFONTは非常にマイナーな言語らしく，有名な（GUI）エディタはほとんどMETAFONTをサポートしていません。

というわけで「METAFONTを使いたい奴はEmacsかVimだ!」[^3]と終わらせても良いのですが，いかんせん自分のようなライトユーザーにとってCUI環境は若干敷居が高いので[^4]，METAFONTに対応しているGUIエディタをご紹介します。

##Mac(,Unix)向けエディタ

### CotEditor

 公式ページは[こちら](http://coteditor.com)。Mac界では言わずと知れた有名エディタですね。**2015年中にはMETAFONTに対応する予定です**~~（実は私の作成したMETAFONTシンタックススタイルが次リリースのバージョン2.3.2から組み込まれるのですが，公開の前にアドベントが回ってきてしまいました…）。~~

2015/12/19追記：バージョン2.3.3がリリースされ，METAFONTに対応しました。

### Kate
 
 公式ページは[こちら](http://kate-editor.org)。Linux界隈では有名なエディタらしいですが，Mac版も存在するようです。

##Windows向けエディタ

### Emerald Editor

  公式ページは[~~こちら~~](http://www.emeraldeditor.com)（2015年12月18日現在，なぜかリンク切れ...）。昔から存在する[Crimson Editor](http://www.crimsoneditor.com)というエディタの後継らしく，将来的にはMacやLinuxにも対応する予定だそうです。



[^3]: EmacsとVimにはいずれもMETAFONT用の編集モードが備わっています。 

[^4]: 前節でターミナルを持ち出た癖にアレですが，私自身日常的に使っているエディタはTeXShopくらいなので，EmacsにもVimにも全然慣れていません。

#METAFONTの文法

さて肝心の文法ですが，こんなサンプルコードを追っていくことにしましょう。

~~~ METAFONT:dangerous_bend.mf

mode_setup;

h_height# := 7.5pt#;
u# := 20/36pt#; baselinedistance# := 11pt#;
define_pixels(u,baselinedistance);
rulethickness# := .5pt#; heavyline# := 50/36pt#;
define_blacker_pixels(rulethickness,heavyline);

beginchar(65,25*u#,h_height#,0); "Dangerous bend symbol";
  pickup pencircle scaled rulethickness; top y1 = 25/27h; lft x4 =0;
  x1 + x1 = x1a + x1b = x4b + x2a = x4 + x2 = x4a + x2b = x3b + x3a = x3 + x3 = w;
  x4a = x4b = x4 + u; x3b = x1a = x1 - 2u;
  y4 + y4 = y4a + y4b = y3b + y1a = y3 + y1 = y3a + y1b = y2b + y2a = y2 + y2 = 0;
  y1a = y1b = y1 - 2/27h; y4b = y2a = y4 + 4/27h;
  draw z1a .. z1 .. z1b --- z2a .. z2 .. z2b --- z3a .. z3 .. z3b --- z4a .. z4 .. z4b --- cycle; %標識のボード
  x10 = x11 = x12 = x13 = .5w - u; x14 = x15 = x16 = x17 = w - x10;
  y10 = y14 = 28/27h; bot y13 = -baselinedistance;
  z11 = (z10 .. z13) intersectionpoint (z1a{z1a - z4b} .. z1{(1,0)});
  y15 = y11; y16 = y12 = -y11; y17 = y20 = y21 = y13;
  draw z11 -- z10 -- z14 -- z15; draw z12 -- z13; draw z16 -- z17; %道標
  x20 = w -x21; x21 - x20 = 16u; draw z20 -- z21; %土台
  x36 = w -x31; x36 - x31 = 8u; x32 = x33 = x36; x31 = x34 = x35;
  y31 = -y36 = 12/27h; y32 = -y35 = 9/27h; y33 = -y34 = 3/27h;
  pickup pencircle scaled heavyline;
  draw z32{z32-z31} .. z33 --- z34 .. z35{z36 - z35}; %急カーブの印
  pickup penrazor xscaled heavyline rotated (angle(z32 - z31) + 90);
  draw z31 --z32; draw z35 -- z36; %上側/下側の横棒
  labels(1a,1b,2a,2b,3a,3b,4a,4b,range 1 thru 36);
endchar;
shipit; end.
~~~

…言わずと知れた「あの文字」（下図）を表すコードです[^5]。

[^5]: 『METAFONTブック』に登場するソースコードの抜粋を，単独で動くように私が手を加えたものです。

<img width="106" alt="dangerousbend.png" src="https://qiita-image-store.s3.amazonaws.com/0/77110/f37e395c-f024-2abf-7417-48ccf0233af7.png">

大雑把に言って，METAFONTのソースコードは**プリアンブル**（的なもの）と**文字の描画部**の2要素で構成されます。`beginchar`から`endchar`までが**文字の描画部**で，その前にちょろっとあるのが**プリアンブル**です。

あと，コードの見かけから何となく分かりますが，**METAFONTの各種コマンドは末尾にセミコロン`;`が必要です。**TikZと同じノリですね。それから，TeX同様`%`以下はコメントとみなされます。

>ちなみに，この「文字」を実際にTeX文書内で使用する方法は，[こちらの記事](http://hak7a3.hatenablog.com/entry/20131207/1386414813)に詳しく記載されています（texadventでもMETAFONTネタは何だかんだ毎年1回は出てくるみたいですね）。
>なお，リンク先の記事で登場する`mktextfm`は内部で`mf`コマンドを実行しているので，ユーザーがわざわざMETAFONTを起動する必要はありません。

## プリアンブル（的なもの）について

**プリアンブル**では，フォントファミリー全体で共通のパラメーターを用意したり，出力装置に合わせた解像度の設定を行ったりします。


### 適切な解像度の設定

冒頭の`mode_setup`は，出力装置に合わせた解像度の設定を行なってくれるコマンドです。METAFONTには`\mode`という特殊な引数が存在し，適切な設定を施すと同じソースから低解像度用・高解像度用など複数のフォントを生成できたりします（これを入れなくともなぜか処理は通りますが，モードによる場合分けが効かなくなるようです）。

例えば，

~~~bash
$ mf \mode=cheapo; input myfont;
~~~

としたら低解像度用のフォントが生成されて，

~~~bash
$ mf \mode=luxo; input myfont;
~~~

としたら高解像度用のフォントがでてくる…なんて事が可能です[^6]。

[^6]: `cheapo`と`luxo`はMETAFONTで既に用意されているモードですが，一般には予め`mode_def`などを使い，（TeXのマクロのように）「このモードでは何をどうすべきなのか」を指定しておく必要があります。

### 変数の設定

ソースから分かる通り，METAFONTにおける変数への値の代入（と同時に変数の宣言）は`:=`で行います。読めば分かると思いますが，例えば`baselinedistance#`は11pt，すなわち1/72.27インチの11倍の大きさを格納しています。これらの末尾に存在する`#`は**「本当の」**値を意味しており，`\mode`によらず絶対に11ptそのものを表し続けます。

`define_pixels`と`define_blacker_pixels`は，`mode_setup`とも関連しますが**「本当の」**値を`\mode`に応じた値（ピクセル数）に変換するコマンドで，同じ11ptの`baselinedistance#`であってもひとたび`define_pixels`を通せば，高解像度用の出力と低解像度用の出力で値が変わることになります[^7]。

例えば1ptをピクセル（の1辺の長さ）3個分で表現する低解像度の印刷機向けモード `cheapo`で処理すると`baselinedistance`の値は33となり，ピクセル30個で表現する高解像度モード `luxo` で処理すると330となるわけです。

`define_blacker_pixels`は，`define_pixels`よりもほんの僅か大きめに値を変換するコマンドです。例えば`rulethickness`は0.5ptなので，`cheapo`モードであればそれは1.5という値に変換されるべきなのですが，`define_blacker_pixels`を通すとその値にさらに0.65上積みされた，2.15という値に変換されます。

このコマンドで処理している変数の名 (`rulethickness`,`heavyline`)から想像出来る通り，`define_blacker_pixels`は「線の幅」の変換専用にチューニングされた`define_pixels`だと思ってくれて差し支えありません。なぜ`define_pixels`本来の変換結果よりも僅かに値を大きめに取るのかと言うと，「インクの滲み」を考慮に入れるためだからだそうです。印刷機あるいは用紙などによって，インクの滲み具合は当然異なるわけですから，それぞれに対応するモードで「値の上乗せ程度」を別個に設定すればどこでも同様な出力が得られるという訳です。Knuthのこだわりが垣間見えますね…。

なお，特にモードを指定せず処理した場合も，自動的に`proof`モードで処理されるため，エラーが出ることはありません。

[^7]: 正確には，`cheapo`では1ptを2.7674ピクセルで表現し，`luxo`は27.674ピクセルで表現するように設定されています。

## 文字の描画部について

`beginchar`の後に続く引数は，それぞれ順に「文字コード」「幅」「高さ」「深さ」を表します。「文字コード」にはASCII文字コード（10進数）を指定するか，`"0"`のように相当する文字を引用符で囲んで入れれば良いです。サンプルでは`65`すなわち小文字のaに対応する字形として，dengerous bendを作成しています。

描画の大まかな流れとしては，

1. 各点の座標を設定
2. `pickup`で線の種類を指定
3. `draw`で各点間を結ぶ

となります。この「各点の座標を設定」する方法がMETAFONT特有で，なんと**連立方程式を自動で解いてくれるのです**。普段からTeXでプログラミングをしていると，これが物凄く便利に感じられますね！

なお，METAFONTでは各点の位置ベクトルを z1, z2, z3, ... と表し，それらの位置ベクトルのxy座標をそれぞれ x1, x2, x3, ...,　y1, y2, y3, ... と表現します[^8]。

具体的には例えばサンプルのこの部分，

~~~
  lft x4 =0;
  x1 + x1 = x1a + x1b = x4b + x2a = x4 + x2 = x4a + x2b = x3b + x3a = x3 + x3 = w;
  x4a = x4b = x4 + u; x3b = x1a = x1 - 2u;
~~~

単に連立方程式を列挙したけですが，これだけで点 z1, z1a, z1b, z2,..., z4 までの x 座標が指定されたことになります（`lft`はその点を通る線の左端を，指定した座標に揃えるコマンド）。

また，`draw`は`..`で連結した点をいい感じにベジェ曲線で結び，`--`は直線で結びます。`---`は「無限の張りをもつ結合」で，両端の先の曲線と滑らかに繋がるような，直線に近い曲線となります。

結局のところ，各点はdengerous bendの以下の部分に対応しています。
![mfput.jpg](https://qiita-image-store.s3.amazonaws.com/0/77110/dc4903ba-b1e7-702f-6ea1-27cf3204b51b.jpeg)
線の細い長方形は，「TeXで文字の大きさとみなされる部分」を表します。従って，TeX文書内でこの文字を使用した場合，標識の下半分がベースラインからはみ出ることになります[^9]。それにより，文字の上下幅がちょうど2文字分となり，以下のようにきっちり組版することが出来るわけです。

<img width="901" alt="The_TeXbook.png" src="https://qiita-image-store.s3.amazonaws.com/0/77110/30562986-81dc-8caa-625d-1f907626382e.png">

> *The TeXbook* (Donald E. Knuth) の組版例

# まとめ

某Adobeさんが開発中の[Project Faces](http://gigazine.net/news/20151008-adobe-project-faces/)~~のパクリ~~と同じサービス，METAFONT / MetaPostで作れないかなぁ...

[^8]: 正確には，サンプルにも登場してる`z1a`のように， [x, y, z] + (英数字) は点 (英数字) とみなされます。
[^9]: コード内で`baselinedistance`が11pt（に相当するピクセル数）に設定されているため，点z13, z17, z20, z21が11ptぶん下に潜ります。そもそもこの文字は，本文中の文字を11ptで組版する際に使用することを想定されています。