Hatena::ブログ(Diary)

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

2011-09-29

dvipdfmx で OpenType する件について (4)

前回の続き)

前回の一連の作業では、LY1 エンコーディングを用いた。LY1 は収録文字範囲の割と貧弱な(Latin-1 または CP1252*1程度をカバーする)フォントに対して用いるには最適である。しかし、「M+ フォント」は日本で制作されたフリーフォントとしては珍しくかなり広い欧文の収録範囲をもち、また配布ページにはわざわざ「T1 エンコーディングに完全対応する」旨が書かれているので、折角だから T1 を使いたい。他の理由として、LaTeX で LY1 を(他のエンコーディングと混ぜて)使うのは fontenc を「ちゃんと」使う必要があって若干高度な話になる。*2というわけで、今回は次の作業を行ってみる。

  • T1 および TS1 エンコーディングを採用する。*3
  • 自動変形による斜体のサポート。
  • (おまけ)pdfTeX でも使えるようにしてみる。

エンコーディングファイルの在り処

斜体は後回しにして、通常(直立体)のフォントについて、T1/TS1 用の TFM ファイルを otftotfm で生成することを考える。これについては、エンコーディングファイルが LY1 のもの(texnansi.enc)から T1/TS1 のものに変わるだけでよさそうである。しかし T1/TS1 の .enc ファイルは一体どこにあるだろうか。

  • TeX Live の場合は、Kpathsearch で探して*4見つかる ec.enc と q-ts1-uni.enc を用いるのがよいだろう。
  • W32TeX の場合、Kpathsearch で見つかる ec.enc *5は致命的に間違っているので、CTAN から fontname パッケージ(以前に述べた、Berry 規則の文書があるパッケージ)を入手して、その中の ec.enc と q-ts1-uni.enc(TeX Live にインストールされているのはこれと同じもの)を用いる。
  • ちなみに、今までちゃんと述べていないが、本来は、エンコーディングファイルを用意するのはずっと大変な作業である。エンコーディングファイルの中に書かれているのは「グリフ名(glyph name)」の列であるが、「同じグリフ(文字)」であっても、フォントによりグリフ名が異なる可能性がある。*6だから、本当なら、フォントのグリフイメージと名前の一覧を見て、「そのフォント専用」の T1 エンコーディングを構成する正しいグリフ名のリストを手作業で作る必要があるのである。*7では今までの作業で、「どこかから持ってきた .enc ファイル」で代用できているのは何故か。実は、otftotfm が「何か上手いことやって」指定した .enc ファイルから「そのフォント用の正しい .enc ファイル」(これが出力に含まれる a_??????.enc というファイルである)を作っているのである。*8だから、例えば Latin Modern フォントが用意している lm-ec.enc や lm-ts1.enc を使っても上手くいくかも知れない。結局のところ不確実でやってみないと解らない。*9

エンコーディングファイルさえ得られれば、あとは LY1 の時の作業と同じである。今回は後の作業のため、マップ情報をファイル temp.map に書き出しておく。まず Thin ウェイトについて otftotfm を実行する。

otftotfm --no-type1 --no-dotlessj -f kern -f liga --mapfile=temp.map -e ec.enc -n mplus1p-a-t1 mplus-1p-thin.ttf
otftotfm --no-type1 --no-dotlessj -f kern -f liga --mapfile=temp.map -e q-ts1-uni.enc -n mplus1p-a-ts1 mplus-1p-thin.ttf

斜体用の TFM の生成

「M+ フォント」には(多くの日本語フォントと同じく)「斜体」のフォントは用意されていない。しかし大抵のレンダラ/DVI ウェアには、フォントのもつ字形をその場で変形(斜体化と幅の伸縮)して出力する機能を持つ。ここではそれを利用して斜体のフォントを補ってみよう。合成斜体はレンダラの側の機能だから、TeX から見れば本物の斜体のフォントがあるのと同じ扱いのはずで、従って、斜体のフォント用の TFM が別に必要となり、さらに、それは直立体とは別のメトリックをもつはずである。otftotfm では -S--slantオプションを付けることで「合成斜体としての TFM」を作ることができる。

otftotfm --no-type1 --no-dotlessj -f kern -f liga --mapfile=temp.map -S 0.167 -e ec.enc -n mplus1p-ao-t1 mplus-1p-thin.ttf
otftotfm --no-type1 --no-dotlessj -f kern -f liga --mapfile=temp.map -S 0.167 -e q-ts1-uni.enc -n mplus1p-ao-ts1 mplus-1p-thin.ttf

ここで -S に指定する値は「水平変位÷垂直変位」(鉛直方向からの勾配値)である。*10TFM 名には斜体を表す Variant 値「o」を追加したものを用いた。

これで 1 つのウェイト(Thin)についての全てのシェープ(T1/TS1;直立/斜体)を生成し終えた。これを残りの 6 つのウェイトについて繰り返す。

dvipdfmx 用のマップファイルの作成

この段階で、temp.map は以下のようになっているはずである。

[temp.map]
% Automatically maintained by otftotfm or other programs. Do not edit.

mplus1p-a-t1--base mplus-1p-thin "AutoEnc_op... ReEncodeFont" <[a_op3mbq.enc <mplus-1p-thin.ttf
mplus1p-ao-t1--base mplus-1p-thin "0.167 SlantFont AutoEnc_op... ReEncodeFont" <[a_op3mbq.enc <mplus-1p-thin.ttf
mplus1p-a-ts1--base mplus-1p-thin "AutoEnc_yh... ReEncodeFont" <[a_yh4sjf.enc <mplus-1p-thin.ttf
mplus1p-ao-ts1--base mplus-1p-thin "0.167 SlantFont AutoEnc_yh... ReEncodeFont" <[a_yh4sjf.enc <mplus-1p-thin.ttf
%(以下他のウェイトについて同様の記述)

以前に述べたようにこれは pdfTeX 用の形式である。だからこれを dvipdfmx 用の形式に書き直す。dvipdfmx のマップにおいて、合成斜体を指定したい場合は、実フォント名の後に「-s〈値〉」を書くことになっている。従って、上で示した部分に対応する記述は次のようになる。

[mplus1p.map]
mplus1p-a-t1--base a_op3mbq.enc mplus-1p-thin.ttf
mplus1p-ao-t1--base a_op3mbq.enc mplus-1p-thin.ttf -s 0.167
mplus1p-a-ts1--base a_yh4sjf.enc mplus-1p-thin.ttf
mplus1p-ao-ts1--base a_yh4sjf.enc mplus-1p-thin.ttf -s 0.167

実際にはこの 7 倍の量の記述があるわけだから、手作業でやるのは大変である。何かスクリプトを書いた方が早くて確実だろう。

#!/path/to/perl
while (<>) {
  m/^ (mplus1p-\S+) \s+ \S+ \s+
    " (?:(\S+) \s+ SlantFont \s+)? AutoEnc_\w+ \s+ ReEncodeFont " \s+
    <\[ (a_\w+).enc \s+ <(mplus-\S+.ttf) $/x or next;
  $t = $2 && " -s $2";
  print "$1 $3 $4$t\n";
}

(うん、まだ続く…)

*1:Latin-1(ISO-8859-1)の Microsoft 独自拡張版。

*2LaTeX で無設定で使えるのは OT1/T1/TS1 だけだから、\usepackage[LY1]{fontenc} として LY1 を有効化する必要があるが、これだけだと既定が LY1 になるため「LY1 で使いたいフォント」以外にも影響が出てしまう。そこで、\usepackage[LY1,OT1]{fontenc} のようにオプション部の LY1 の後に「実際に既定にしたいもの」を改めて書く必要がある。

*3:Latin-1 にある「普通」の記号で T1 に入っていないものが TS1 にあるので、T1 をサポートするなら TS1 も含めるのが望ましい。

*4:つまり「kpsewhich ec.enc」を実行して表示されるパスのファイル。

*5:$TMF/fonts/enc/dvips/base/ec.enc。なお、同じディレクトリにある cork.enc は正しい T1 エンコーディング(の一種)のように見える。

*6:例えば T1 の符号位置 32 にある〈␣〉(U+2423)には visiblespace、visualspace、uni2423 等のグリフ名が使われている。もちろん頻出する文字については慣習的に定まっている(例えば〈Q〉→ Q、〈5〉→ five、〈#〉→ numbersign)。

*7TeX システムのインストールの中に「T1 エンコーディング」に相当するはずの .enc ファイルが大量に存在するのはそのためである。

*8:多分こんな動作をしているのだと思う:入力エンコーディングの中に visiblespace があったとする。otftotfm は「visiblespace は U+2423 を表すのに使われる」という知識を持っている。従って、入力の OpenType フォントの U+2423 に対するグリフを(Unicode cmap を使って)得て、そのグリフ名を調べて、その名前を出力のエンコーディングに書き込む。もし、該当のグリフがフォントになかった場合は一般には .notdef に置き換えられるが、確かこの文字の場合は VF を使って合成していたはずである。

*9:ちなみに、ttf2tfm は「エンコーディングの修正」をする機能がない。otftotfm でも .enc ファイルを -e--encoding)でなく --literal-encoding で渡すと修正が行われなくなる。

*10TFM の保持する SLANT 値と同じ定義。敢えて角度を持ち出して「θだけ傾ける」という場合は、tan θ の値ということになる。