マクロツイーター

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

「IPAmj明朝」のグリフ名情報の話

OpenType フォントでは基本的に個々のグリフは「グリフ ID(GID)」と呼ばれる番号で管理されている。*1しかし、TrueType グリフの OpenType フォント(以下「TrueType フォント」と呼ぶ)では、Type1 フォントと同様に、グリフに名前(グリフ名)を付けることができて、フォントを使うアプリが対応していれば、Unicode 符号値や GID の代わりに「グリフ名」で特定のグリフを呼び出すことができる。

ツイートの内容は、「IPAmj明朝」のグリフ名テーブルが、現行の OpenType 仕様から見ると異常ではないかという疑問である。

不可解な警告

dvipdfmx で IPAmj明朝(ipamjm.ttf)を埋め込んだ PDF を作成しようとする。*2

\documentclass{article}
\usepackage{pxchfon}
\setminchofont{ipamjm.ttf}
\begin{document}
マジ明朝!
\end{document}

これを dvipdfmx で変換させる*3と、次のように大量の警告メッセージが出る。

test.dvi -> test.pdf
[1
** WARNING ** TrueTypes post table name index 32768 > 32767
** WARNING ** TrueTypes post table name index 32769 > 32767
……(56613行省略)……
** WARNING ** TrueTypes post table name index 61075 > 32767
** WARNING ** TrueTypes post table name index 61078 > 32767
]
** WARNING ** UCS-4 TrueType cmap table...
** WARNING ** Format 12 cmap table ... untested
** WARNING ** UCS-4 TrueType cmap table...

7307 bytes written

PDF 文書自体は出力されていてその内容は正常に見えるが、このように大量の警告が出るのは dvipdfmx とフォントのどちらかが間違っている可能性が高い。そこでフォントに格納されたグリフ名について調べてみた。

グリフ名の格納方法

ここでは、フォントファイル内でグリフ名が格納されているかをやや抽象的に述べる。TrueType フォント*4では、「GID → グリフ名」の対応情報は次のような形式で格納されている。なお、以下では具体例として「IPAex明朝(Ver001.03)」を用いた。

  • グリフ名インデクスのリスト: 「IPAex明朝」では以下の通り。

    0, 258, 259, 260, ……, 12472, 12473, 12474*5

    0〜65535 の範囲の整数からなるリストで、その長さはグリフの個数(例では 12218 個)に等しい。これは、「GID → グリフ名インデクス」の対応を表している。即ち、「GID 0 → インデクス 0」、「GID 1 → インデクス 258」、……、「GID 12217 → インデクス 12474」と解釈される。
  • 独自グリフ名のリスト:「IPAex明朝」では以下の通り。

    .null, CR, aj1, aj2, aj3, ……, aj9357, aj15882, aj20301

    これは文字列からなるリストである。例では 12217 個の文字列が並んでいる。

これらの他に、次の固定(フォントに依存しない)のグリフ名リストが用いられる。

  • Mac 標準グリフ名のリスト: Apple の解説ページの中程にあるもの。

    .notdef, .null, nonmarkingreturn, space, exclam, ……, Ccaron, ccaron, dcroat

これらの 3 つのリストを用いて、「GID → グリフ名」の対応が決められる。即ち、GID が g のグリフの名前は以下のように決まる。*6

  • グリフ名インデクスの g 番目の要素(GID g に対するインデクス)を n とする。
  • n の値により次のように GID g のグリフ名を決定する。
    • n が 0〜257 の範囲にある場合: グリフ名は「Mac 標準グリフ名のリスト」の n 番目にある文字列。
    • n が 258〜32767 の範囲にある場合: グリフ名は「独自グリフ名のリスト」の (n − 258) 番目にある文字列。
    • n が 32768〜65535 の範囲にある場合: 将来の使用のため予約。つまり未定義。
  • 「IPAex明朝」の場合のグリフ名決定例。
    • GID 0 のグリフ名は? → インデクスは 0、よって「標準」のリストの 0 番目(先頭)にある .notdef。
    • GID 3 のグリフ名は? → インデクスは 260、よって「独自」のリストの 2 番目にある aj1。
    • GID 12217(最後)のグリフ名は? → インデクスは 12474、よって「独自」のリストの 12216 番目(最後)にある aj20301。

IPAmj明朝の場合

「IPAmj明朝」では、上で述べた 2 つのリストは次のようになっている。

  • グリフ名インデクスリスト

    0, 258, 259, 260, ……, 61073, 61074, 61075, 61078 (長さ 60819)
  • 独自グリフ名リスト

    .null, CR, aj1, aj2, ……, mj068099, mj068100, mj068101, mj068056 (長さ 60870)

「グリフ名インデクスリスト」については、一部抜けがあるが連続した整数が並んでいる。ところが、このフォントはグリフが 60819 個もあるので、このリストの後半にある値はどれも 32767 を超えてしまう。規格に厳密に従うならこれは「グリフ名の解釈法が未定義」ということになる。普通はそんな値を指定することは考えられないので、dvipdfmx が警告を出すのも納得できる。しかし、dvipdfmx は和文フォントを扱う時にはグリフ名を全く使わない(基本的に GID を用いる)のでこれにより出力が異常になることもなさそうである。

意図されたグリフ名は何か?

フォント製作者の意図はもちろん「未定義」ではなく何らかの名前に解決されることであろう。「独自グリフ名リスト」が 32510 を超える長さ*7を持っていることを考えると、恐らくは「インデクスが 32767 を超える場合にも 258〜32767 の範囲の場合と同じ解釈をする」ことが意図されているのであろう。即ち、GID 60818(最後)のグリフ名は「独自グリフ名リスト」 60820(= 61078 − 256)番目の名前である mj068052 とすべきなのだろう。

実際に GID 60818 のグリフが何であるかを調べてみる。

% upLaTeX 文書
\documentclass{article}
\AtBeginDvi{\special{pdf:mapline uprml-h Identity-H ipamjm.ttf/I}}
\begin{document}
\jfont\uprml=uprml-h \uprml \kchar60818
\end{document}

これを組版すると〈暳〉の文字が現れる。文字情報基盤整備事業のサイトの文字検索システムを用いて、「MJ068052」を検索すると、同じ文字が結果として出てきた。どうもその解釈で正しいらしい。

*1:例えば、GSUB 的な属性は「この番号のグリフをこの番号のグリフで置き換える」という指示を行うものである。

*2:この現象自体は ipamjm パッケージを試していて気付いたものだが、以下の説明からわかるように ipamjm パッケージとは無関係である。なお、IPAmj明朝は普通の Unicode フォントとしても使用できることに注意。

*3:もちろん、ipamjm.ttf を適切に配置した上で。

*4:post テーブルのバージョンが 2.0 の場合。もしこのテーブルのバージョンが 3.0 の場合はフォントは「グリフ名を持っていない」ことになる。CFF グリフ OpenType の場合は必ず 3.0 である。

*5:先頭の 0 を除けば連続した整数が並んでいる。

*6:以下の説明で「〜番目」という場合、先頭を「0 番目」と数える。

*7:規格に従うと、この長さを超える部分は全く無用である。