Hatena::ブログ(Diary)

マクロツイーター このページをアンテナに追加 RSSフィード Twitter

2011-10-04

dvipdfmx で OpenType する件について (SFD 編-1)

昨日の記事で述べたように、日本語(一般に CJK 言語)の OpenType に対して「.enc ファイル + dvipdfmx」の組み合わせで欧文フォントTFM)を対応させようとすると、一部の環境で文字が表示されないという状況に陥る。そして、それを回避する方法として、サブフォント定義ファイル(SFD ファイル)を使う方法を試行した。「SFD ファイルを使えば上手くいく」ということが判っても、それを使ったフォント導入方法が判らないと意味がないので、これからその導入方法を説明しようと思う。ただし、この方法は SFD ファイルの本来の用法を外れたトリック的なものである(だから他ではこの方法は解説されていないと思う)ので、まずはその「本来の用法」についての解説から始めたい。

サブフォントとは

サブフォントとは、8 ビット欧文 TeX (1 つの欧文フォントが高々 256 文字を含む)の上で Unicode のような大規模な符号化文字集合を扱うための技法の一つであり、CJK パッケージ等で使われている。原理は単純で、要するに大規模な元エンコーディング文字集合)を(高々)256 文字毎に分割することで、「元エンコーディングをもつ 1 つのフォント」を「複数の 8 ビットフォントTFM)」で表すというものである。この場合、元エンコーディングの符号位置から後者の表現への変換は TeX マクロで行い、それを前者(元の符号位置)に戻す作業を DVI ウェアが行うことになる。*1

例えば、「Unicode BMPエンコーディングをもつ『M+ 1P Regular』」のことを “mplus1p-r-u”*2と呼ぶことにして、これをサブフォントで表すことを考える。Unicode BMP の場合、符号空間は U+0000〜U+FFFF (256×256 文字)なので、単純に符号値順に 256 文字毎に分割する方法が標準的である。*3

  • 「M+ 1P Regular」の U+0000〜U+00FF を順に収めた TFM を mplus1p-r-u00 とする;
  • 「M+ 1P Regular」の U+0100〜U+01FF を順に収めた TFM を mplus1p-r-u01 とする;
    …………
  • 「M+ 1P Regular」の U+FF00〜U+FFFF を順に収めた TFM を mplus1p-r-uff とする。

つまり、「mplus1p-r-u00, …, mplus1p-r-uff の 256 個の TFM」が論理的な “mplus1p-r-u” を表しているといえる。

仮にこの “mplus1p-r-u” がインストールされた TeX システムがあれば、そこでの(8 ビット欧文の)TeX で次のようにしてUnicode 文字列高徳納 〈9AD8 5FB3 7D0D〉」を「M+ 1P Regular」で 出力することができる。

% \printchar{<TFM>}{<符号位置>}: 指定のフォントで指定の符号位置の文字を出力
\def\printchar#1#2{{\font\tempFont=#1\relax \tempFont\char#2\relax}}
% 「高徳納」=〈9AD8 5FB3 7D0D〉
\printchar{mplus1p-r-u9a}{"D8}%
\printchar{mplus1p-r-u5f}{"B3}%
\printchar{mplus1p-r-u7d}{"0D}%

ここでは非常に単純なマクロを用いたが、これをもっと発展させれば、例えば「UTF-8 で書いたソースを読んで Unicode 文字をサブフォントで出力する」ことも可能であることは容易に想像できるだろう。CJK パッケージは実際にそういう処理を行っているのである。*4

サブフォントTFM の生成方法

では、先に述べた “mplus1p-r-u”、つまり mplus1p-r-u??.tfm の 256 個の TFM ファイルはどうしたら生成できるか。要求仕様が定まっているので、これまでの記事を読んだ人なら、方法を考えるのは容易いであろう。例えば、mplus1p-r-u4e.tfm は U+4E00〜4EFF の 256 文字が並んでいるはずなので、次のようなエンコーディングファイル gen-u4e.enc を作ればよい。

/gen-u4e [
  /uni4E00 /uni4E01 /uni4E02 …… /uni4EFF
] def

その上で、次のようなコマンドを実行する。*5

otftotfm (他オプション) -e gen-u4e.enc -n mplus1p-r-u4e mplus-1p-regular.ttf

ここで生成された(カスタマイズされた)エンコーディングファイルを mplus1p-u4e.enc と改名した(元は a_??????.enc の形の名前)とすると、dvipdfmx では次のようなマップ行を作ればよい。*6

mplus1p-r-u4e mplus1p-u4e mplus-1p-regular.ttf

これを全ての TFM について繰り返す。結果的に 256 個の .enc ファイルと、256 行からなるマップが出来上がる。

mplus1p-r-u00 mplus1p-u00 mplus-1p-regular.ttf
mplus1p-r-u01 mplus1p-u01 mplus-1p-regular.ttf
……(253 行省略)……
mplus1p-r-uff mplus1p-uff mplus-1p-regular.ttf

TFM を作る作業の手間に関してはバッチ化すれば抑えられるとして、マップファイルの記述について、1 つのフォントあたり 256 行のほとんど同じ行が繰り返すのはあまり嬉しくない。

(続く)

*1:念のため繰り返すと、一旦別の(煩雑な)形式に置き換えている理由は、8 ビット TeX は 8 ビットの符号値しか発生させられないからである。

*2:ここの説明から判るように、この mplus1p-r-u というフォントは「論理的」にしか存在しない。(「仮想的」といってもよいが、VF とは異なる技法である。)ただし、DVI ウェアでの設定法として、「実物の mplus1p-r-u」が使われる可能性はある。

*3:しばしば「Unicode サブフォント」と呼ばれる。

*4:実際に、 “mplus1p-r-u” が使用可能な状態で、ファミリ mplus1p に対する「C70」という(やや特殊な)フォント定義ファイル(c70mplus1p.fd)を書けば、このフォントを CJK パッケージでの UTF8 エンコーディングのファミリとして用いることができる。

*5:ここは飽くまで原理を説明しているので詳細は省く。そもそも、原理としては正しいのだが、実際には、先日述べた「異常現象」のせいで、この方法は残念ながら使えない……。

*6:otftotfm が VF を作った場合は、マップに指定する TFM 名は --base が付くだろうが、そういう詳細は省いて説明している。