TeX の PL ファイルを知ってみよう

:::note info
これは「[TeX & LaTeX Advent Caleandar 2022](https://adventar.org/calendars/7868)」の20日目の記事です（大遅刻）。
（19日目は [yukishitaさん](https://qiita.com/Mopepe51/items/8b2307e0e057c499e2de)，21日目は [mattskalaさん](https://ansuz.sooke.bc.ca/entry/386)です。）
:::

## PL ってどんなファイル？
一口に言うと「**人間が簡単に読める，TeXが組版する上で必要な文字情報が書かれたファイル**」です．
普通に TeX, LaTeX を使って組版をしている人は，まず触れないでしょう．また，チョットフォントいじってる人でも目にしたことのある人は少ないでしょう．

PL には，TeX が文字を組版する上で必要とする情報がすべて[^not_all]記述されています．
例えば，文字横幅・縦幅，スラントならスラント角度，空白の大きさ，リガチャ，カーニング， e.t.c. などの情報が記述されています．
ただし，**グリフ（概形）は記載されていません**．「A」という一文字が，どんな幅や高さかという情報は持っていますが，どんな形をしているかは書かれていないということです．これは，TeX は組版をする上で，どんな形をしているかを知る必要がないからです．

<div align="center">
<img  width="300" alt="Glyf.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/945547/e3c839a4-427a-5141-1881-d884303b801e.png">
</div>

 

PL の説明のために，少しイマドキのTeXを使った組版の流れを整理してみましょう．
TeX は，TFM や FD を使って文字や線の位置を記述した組版結果として DVI を出力します．
この DVI を，例えば dvipdfmx に処理させます．このとき，dvipdfmx は OTF などからグリフを引っ張ってきて，決められた位置に一文字ひと文字書き込み，これを PDF として出力します．

<img  width="800" alt="tex2dvipdfmx.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/945547/5b8a0f57-7e4b-e465-e021-74ee7a3c0e69.png">

そう，TeX は文字を組版するとき，TFM しか見ていません！
すなわち，TFM を調整することで，組版結果を変えることができます．

しかし，TFM は TeX が読むための形式（バイナリ形式）ですので，人間が読み書きするのは困難に等しいです．
これを人間が簡単に読める形（テキスト形式），すなわち人間のためのファイル形式したものが，PL ファイルなのです．
当然ですが，PL と TFM は完全に互換で，相互変換が可能です．

<img  width="600" alt="bin.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/945547/e8a1fcf1-e91e-9a79-0d35-7b843451442a.png">



TFM は通常ソフトウェアが書き出すものです．METAFONT や FontForge などでは TeX 専用に書き出せます．そのため，実際に人が直接手を加えることは少ないです．高度に自身で調整するという奇特な人はぜひやってみましょう！


## PL を実際に見てみる
``fonts\tfm\public\cm``にある``cmr10.tfm``の中身を見てみましょう[^cmr]． 

TFM から PL へ変換を行うには`tftopl`を用います．TeXLive などが入っており bin にパスが入っていれば DOS からすぐに使えます．
``cmr10.tfm``を適当なフォルダにコピーし，このフォルダをカレントとし DOS を開き，``tftopl cmr10.tfm``を実行してみましょう．すると...
```
(FAMILY CMR)
(FACE O 352)
(CODINGSCHEME TEX TEXT)
(DESIGNSIZE R 10.0)
(COMMENT DESIGNSIZE IS IN POINTS)
(COMMENT OTHER SIZES ARE MULTIPLES OF DESIGNSIZE)
(CHECKSUM O 11374260171)
(FONTDIMEN
   (SLANT R 0.0)
   (SPACE R 0.333334)
   (STRETCH R 0.166667)
   (SHRINK R 0.111112)
   (XHEIGHT R 0.430555)
   (QUAD R 1.000003)
   (EXTRASPACE R 0.111112)
   )
(LIGTABLE
   (LABEL O 40)
   (KRN C l R -0.277779)
   (KRN C L R -0.319446)
   (STOP)
   (LABEL C f)
   (LIG C i O 14)
   (LIG C f O 13)
   (LIG C l O 15)
（以下省略）
```
ズラズラと表示されたと思います．このままでは表示だけです．ファイルに保存したい場合は第2引数に保存ファイル名を与えます．``tftopl cmr10.tfm　cmr10.pl``を実行すると，``cmr10.pl``に先程 DOS に流れたものが保存されます．

逆に，PL を TFM に変換したいときは``pltotf``を使います．
``pltotf cmr10.pl my_cmr10.tfm``と実行すれば，``my_cmr10.tfm``に保存されます．同じファイル名で保存する場合は第2引数は不要ですが，上書きされることに留意してください．

## PL ファイルを読んでみよう！

PL や TFM ファイルの情報は，アスキーさんが [Web 上](https://asciidwango.github.io/ptex/pl/index.html)に情報を載せてくれています．ここを読めばほとんど理解できます（というか，ここ読んだらこの記事は読まなくてもいいかも）．
『The TeXbook』や『日本語TeXテクニカルブック I』にも詳しく書かれています．[TeXnician の人](https://mobile.twitter.com/wtsnjp/status/1562426126529863682)は何冊も持っているようです．The TeXbook はオンラインで TeX の出力例として（英語ですが）公開されいます．日本語版の『TeX ブック』は中古でも希少で高価ですが，'22時点では手に入ります．テクニカルブックは中古で安価に手に入ります．『The METAFONT book』には PL の情報はあまりありませんが，TFM は少し載っています．



閑話休題，PL ファイルは，プロパティと呼ばれる特性によって管理されています．
プロパティは常にパーレンでくくられています．1行目を見てみましょう．
```
(FAMILY CMR)
```
これは，``FAMILY``というプロパティに，``CMR``が指定されています．「このファイルは，CMR のファミリーですよ」と宣言しています．
このように，``([プロパティ] [値])``という具合でプロパティを用いて様々な特性を設定していきます．
値は複数になることもあります．また，プロパティの中にプロパティが入れ子することもあります．

もう一つ，重要な概念として，数値の表し方が複数あることです．
例えば，4行目を見てみましょう．
```
(DESIGNSIZE R 10.0)
```
これは，「10pt 用のフォントですよ」と書かれいます．10.0 の前にある R は，直後に来る数値の様式を表しています．R の場合は10進数の実数であること表します．他にも以下のような種類があります．

<table>
            <tbody align = "center">
                <tr>
                    <th>R</th><td>10進数の実数</td>
                </tr>
                <tr>
                    <th>D</th><td>0~255の正の10進数の整数</td>
                </tr>
                <tr>
                    <th>O</th><td>符号なし8進数の整数</td>
                </tr>
                <tr>
                    <th>H</th><td>符号なし16進数の整数</td>
                </tr>
                <tr>
                    <th>C</th><td>ASCII文字列</td>
                </tr>
            </tbody>
        </table>

### もっと詳しく読んでみよう！
簡単な概念が見えてきましたか？各プロパティがもっと詳しく知りたい人は[アスキーさんの記事](https://asciidwango.github.io/ptex/pl/index.html)を読んでみてください．
実際にどのように文字の情報が書かれているかを見てみましょう．
8~16行目を見てみましょう．
```
(FONTDIMEN
   (SLANT R 0.0)
   (SPACE R 0.333334)
   (STRETCH R 0.166667)
   (SHRINK R 0.111112)
   (XHEIGHT R 0.430555)
   (QUAD R 1.000003)
   (EXTRASPACE R 0.111112)
   )
```
``FONTDIMEN``プロパティには，フォントの基本的な情報が入っています．詳しくは下図のとおりです．
<img  width="600" alt="FONTDIMEN.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/945547/fc6b442a-3db4-814b-a6a9-53cd5439e3d5.png">

少し行が飛びますが，468~483行目を見てみましょう．
```
(CHARACTER C A
   (CHARWD R 0.750002)
   (CHARHT R 0.683332)
   (COMMENT
      (KRN C t R -0.027779)
      (KRN C C R -0.027779)
      (KRN C O R -0.027779)
      (KRN C G R -0.027779)
      (KRN C U R -0.027779)
      (KRN C Q R -0.027779)
      (KRN C T R -0.083334)
      (KRN C Y R -0.083334)
      (KRN C V R -0.111112)
      (KRN C W R -0.111112)
      )
   )
```
``CHARACTER``は文字のプロパティを設定するプロパティです．この場合 A という文字に設定しています・``(CHARWD R 0.750002)``は文字の幅を，``(CHARHT R 0.683332)``は文字の高さをそれぞれ``CHARWD, CHARHT``というプロパティ指定しています．詳しくは下図のとおりです．

<img  width="700" alt="tex2dvipdfmx.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/945547/55b197d1-689a-6872-2f9d-20ae1753b6eb.png">

''COMMENT''の引数にかかれている内容は無視されます．メモ書きです．




他のプロパティの例も見てみましょう．簡単なリガチャとカーニングの例を示します（17~164行目抜粋）．
```
(LIGTABLE                 # LIGTABLE 開始
(LABEL C f)               # LABEL を文字「f」に指定
(LIG C f O 256)           #「f」と「f」が並んだら八進数256 の文字(ﬀ) に置換
(LIG C i O 257)           #「f」と「i」が並んだら八進数257 の文字(ﬁ) に置換
(LIG C l O 260)           #「f」と「l」が並んだら八進数260 の文字(ﬂ) に置換
(STOP)                    #「f」の終了

(LABEL C V)               # LABEL を文字「V」に指定
(KRN C o R -0.083334)     #「V」と(o) のカーニング
(KRN C e R -0.083334)     #「V」と(e) のカーニング
(KRN C A R -0.111112)     #「V」と(A) のカーニング
(STOP))                   # LABEL「V」終了, LIGTABLE 終了
```
``LIGTABLE``では，リガチャ（合字）やカーニングの設定が書かれています．``LABEL``で指定した文字が``(STOP)``までに書かれたプロパティの内容を設定します．


### 特殊なプロパティ

```
(FACE O 352)
```
ここでは 8 進数に変換されていますが，普通は``F``で指定します．詳しくは[ここ](https://asciidwango.github.io/ptex/pl/format.html)を参照してください．

```
(CODINGSCHEME TEX TEXT)
```
PL(TFM) の大きな属性を決めます．``TEX TEXT``は本文のテキスト用のフォントであることを示しています．
``TEX MATH SYMBOL``や``TEX MATH EXTENSION``は数式用の記号などのフォントであることを示します．

```
(CHECKSUM O 11374260171)
```
TFM と Type1 ファイルの整合性を確認するための値．0 にすることで整合性を確かめなくなります．既存のものを自身でいじった場合は 0 にしておきましょう

```
(HEADER D 18 O 1)
```
TFM のヘッダーに直接書き込むためのものです．普通は使いません．変態のために解説すると，TFM には header 部分があり，header[0] にはチェックサム，header[1] にはデザインサイズ...のようになっています．このとき，header[18] 以降は未定義になっています．ここに何かしらの値を書き込むためのものです．





## もっと高度に PL を見てみよう！！

``fonts\tfm\public\cm\cmsy10.tfm``
を見てみましょう．このファイルは数式のシンボル用のフォントになっています．PL(TFM) は，対になるフォントファイルが存在します．多くは同じファイル名で保存されており，今回であれば``\type1\public\amsfonts\cm\cmsy10.pfb``に保存されています．実際の中身は以下のようになっています．

<img  width="500" alt="cmsy10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/945547/356c87c9-c063-329e-4592-342ea3ad6486.png">


この一文字ひと文字ごとに，幅や高さが設定されています．ここまででは，今までと同じです．
PL ファイルの``CODINGSCHEME``プロパティを見てみましょう．
```
(CODINGSCHEME TEX MATH SYMBOLS)
```
この PL が数式のシンボル用のフォントに設定されています．
面白いことに，このファイルには数式に関するいくつかの寸法（dimension）が設定されています．``FONTDIMEN``プロパティを見てみましょう．
```
   (SLANT R 0.25)
   (SPACE R 0.0)
   (STRETCH R 0.0)
   (SHRINK R 0.0)
   (XHEIGHT R 0.430555)
   (QUAD R 1.000003)
   (EXTRASPACE R 0.0)
   (NUM1 R 0.676508)
   (NUM2 R 0.393732)
   (NUM3 R 0.443731)
   (DENOM1 R 0.685951)
   (DENOM2 R 0.344841)
   (SUP1 R 0.412892)
   (SUP2 R 0.362892)
   (SUP3 R 0.288889)
   (SUB1 R 0.15)
   (SUB2 R 0.247217)
   (SUPDROP R 0.386108)
   (SUBDROP R 0.05)
   (DELIM1 R 2.389999)
   (DELIM2 R 1.01)
   (AXISHEIGHT R 0.25)
```
先程の``cmr10.pl``よりもたくさんのプロパティが設定されています．詳細は，先程の画像に乗せていますが，実際に変更してみましょう．
``NUM``, ``DENOM``では numerator（分子）と denominator（分母）に関する値，つまり分数を構成する値を設定することができます．分数の線（括線）とのアキを設定できます．

<img  width="700" alt="num_demon.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/945547/170fe828-c4b1-552c-96f8-50961ebad483.png">

分子の 1, 3, x の位置に注目してください．オリジナルでは，ベースラインが綺麗に揃っていますが，詰めていくと 1 のみ括線に近づいていきます．

このように，``FONTDIMEN``プロパティには文字への情報だけでなく，組版の情報が含まれています．

他にもみてみましょう．``tfm\public\cmtfm\public\cm\cmex10.tfm``を見てみましょう．これは``TEX MATH EXTENSION``に分類されます．

```
(FONTDIMEN
   (SLANT R 0.0)
   (SPACE R 0.0)
   (STRETCH R 0.0)
   (SHRINK R 0.0)
   (XHEIGHT R 0.430555)
   (QUAD R 1.000003)
   (EXTRASPACE R 0.0)
   (DEFAULTRULETHICKNESS R 0.039999)
   (BIGOPSPACING1 R 0.111112)
   (BIGOPSPACING2 R 0.166667)
   (BIGOPSPACING3 R 0.2)
   (BIGOPSPACING4 R 0.6)
   (BIGOPSPACING5 R 0.1)
   )
```
またまた曩の``FONTDIMEN``とは違いますね．
``DEFAULTRULETHICKNESS``では，数式内の rule の既定値を設定できます．括線の太さや，その他のアキの基準として使われます．
``BIGOPSPACING``から始まるプロパティは大型演算子とその添字のアキを設定できます．
``BIGOPSPACING3``, ``BIGOPSPACING4``は通常のアキ，``BIGOPSPACING1``, ``BIGOPSPACING2``は最小距離になります．下付きの添字の中で分数や上付きの添字などがある場合，大型演算子と添字が近すぎすぎてしまうのを抑制しています．
言葉で説明しても難しいだけので，下図を参考にしてください．

<img  width="700" alt="BIGOPSPACING.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/945547/c866a595-e7af-5940-5844-457c331e64ba.png">


``TEX MATH EXTENSION``では，他にも特殊なプロパティがあります．23~28行を見てみましょう．
```
(CHARACTER O 0
   (CHARWD R 0.458336)
   (CHARHT R 0.039999)
   (CHARDP R 1.160013)
   (NEXTLARGER O 20)
   )
```
``NEXTLARGE``は NextLarge 機構のためのものです．数式のカッコは中身の大きさに合わせて，$\bigr)\to\Bigr)\to\biggr)\to\Biggr)$のように変化していきます．実際にフォントも見て照らし合わせていましょう．

<img  width="400" alt="cmex.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/945547/0c9a9364-dcac-2430-0ca3-43d59e830c91.png">

ファイルで``NEXTLARGE``をたどると``O 0``→``O 20``→``O 22``→``O 40``...と指定されています．実際のフォントでも，この順番で開き丸括弧が大きくなっています．このように順繰りに大きなカッコを指定していきます．ただし，この大きくなる尺度は指定することはできません．


さらに特殊なプロパティである``VARCHAR``を見てみましょう．TeX には合成カッコという概念があります．先程の NextLarge 機構では，とてつもなく大きなカッコを作ることはできません[^big_is_fuzz]．これに対応するためにカッコをパーツごとに分けて合成することで作られたカッコが合成カッコです．下図を見てください．

<img  width="700" alt="VARCHAR1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/945547/5be0a2c3-acbc-63a7-528f-fddb5054c858.png">

このように，カッコをパーツを``REP``(繰返部品), ``TOP``(上部品), ``MID``(中間部品), ``BOT``(下部品)に分解して，``REP`` を繰り返すことで大きなカッコを形成します．
NextLarge 機構の最後は合成カッコにつながっています．
```
(CHARACTER O 40
   (CHARWD R 0.79167)
   (CHARHT R 0.039999)
   (CHARDP R 2.9600315)
   (NEXTLARGER O 60)
   )

（中略）

(CHARACTER O 60
   (CHARWD R 0.875003)
   (CHARHT R 0.039999)
   (CHARDP R 1.760019)
   (VARCHAR
      (TOP O 60)
      (BOT O 100)
      (REP O 102)
      )
   )
```
NextLarge 機構の最後である``O 40``の次は``O 60``であり，``VARCHAR``プロパティにカッコを構成するパーツが登録されています．

## PL を編集せずに値を変更してみる

TeX の中に``fontdimen``というパラメータがあります．これは TFM の FONTDIMEN を TeX 内で調整できるものです．便利ですが，不都合もあり，他のマクロで上書きされたり，逆に干渉して予期せぬ結果を生んでしまう可能性があります．また，デザインサイズに揃えるべきで，例外変更法です．
しかし，一時的に変更する場合などには有用です．例を以下に示します．

```latex
\font\fftemp=cmsy10       % \fftemp にフォント「cmsy10」を代入(fftemp は任意の名前)
\textfont2\fftemp         % \textfont2 へ\fftemp を指定
\fontdimen8\textfont2=5pt % \textfont2 の\fontdimen 8 つ目(NUM1) に5pt を代入
```

## 最後に
これで今日から誰でも PL ファイルを編集できますね！
自作のフォントの調整や，自作の数式記号を組み込むときの寸法の設定までできてしまいます．
ただ，数式に関する寸法が様々なファイルに散らばっているのは，分かりづらいですね．
来年は，TFM を読んでみましょう！
大遅刻，ごめんなさい (×_×)☆＼(^^;)ﾎﾟｶ




## 【余談】あまりにも高度な規則
TeX の数式組版は非常に綺麗に出力されます．その裏ではトンドモナイほど細かい規則があります．

### 特殊な最低限の深さ
下付き添字を付ける際に付ける対象が単純な文字列でない（例えば``\underline{X}_a``など）場合は，ベースラインから最低でも「添字を付ける対象の深さ - ``SUBDROP``」より下に配置されます．

### 分数の天の川
括線と分子・分母は，インラインスタイルでは``DEFAULTRULETHICKNESS``，ディスプレイスタイルでは``DEFAULTRULETHICKNESS``の 3 倍は必ず離される．

### 添字の天の川
対象文字にて下付き上付き添字の両方が付く場合には，``DEFAULTRULETHICKNESS``の 4 倍は必ず離される．

## 【余談】``cmr10.tfm``を上書きしても適用されない．
大前提として，自作でなく，既存で入っている TFM などは上書きしてはいけません．同じ .tex ファイルを (La)TeX で処理しても同じ出力結果が得られないことになります．例では，誰でも共通で持っている TFM ということで紹介したので，大原則上書きしてはいけません．
しかし，中にはオレオレ TeX 環境で，既存のものを上書きして試したい人もいるでしょう．しかし，上書きしただけでは変更されません．``fmtutil-sys -all``を実行しないと反映されません．




[^not_all]:正確には VFM(VPL) を参照することもあります（間違ってたらごめんなさい）．
また，XeTeX は OpenType を直接扱える特性上，TFM(PL) を必要としない場合もあります．

[^cmr]:Computer Modern Roman は TeX の生みの親であるクヌース先生が作ったフォントです．頭文字を取って cmr, 10pt 用だから cmr10 なのです．

[^big_is_fuzz]:管見ですが，意図的でない場合を除き，多くの場合，大きなカッコを使わなければならない状況になるとき，これは小さなカッコになるように分解できるはずです．