マクロツイーター

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

cmap から CMap を作る話

コレ。

何をするものか

Adobe-Identity-0 の CID をもつ日本語 OpenType フォントの cmap 情報(Unicode から CID へのマップの情報)を読みだして CMap ファイルを作るためのもの。これを利用すると、up(la)TeX + dvipdfmx で当該のフォントを埋め込めるようになる。詳しくは doraTeX さんの記事を読んでほしい。

例えば、Source Han Sans(源ノ角ゴシック) の(非サブセットの)OTF 版のフォントファイルの 1 つである SourceHanSans-Medium.otf の CMap を得たい場合は、次のコマンドを実行する。

texlua zrmakecmap.lua SourceHanSans-Medium.otf

※「texlua」は LuaTeX エンジンを Lua インタプリタとして使う場合のコマンド名。*1詳細は別の記事を参照。

これで適当な名前*2(この場合は UniSourceHanSansMedium-UTF16-H)の CMap ファイルを得られる。別の名前を指定したい場合は -o オプションを指定する。*3

texlua zrmakecmap.lua -o UniSourceHanSans-UTF16-H SourceHanSans-Medium.otf

こうして得た CMap ファイル UniSourceHanSans-UTF16-H を実際に使ってみよう。ここでは簡単のため、plain upTeX を用いて、かつ(VF を通さず)直接 TFM のフォントを使うことにする。upTeX の標準の明朝体*4の TFM である uprml-h を Source Han Sans Medium にマップして文字を出力してみよう。このための dvipdfmx のマップ行は以下のようになる。

uprml-h UniSourceHanSansJP-UTF16-H SourceHanSans-Medium.otf

マップ行を TeX ソース内で指定することにしよう。

% plain upTeX 文書, 文字コードは UTF-8
\special{pdf:mapline uprml-h UniSourceHanSansJP-UTF16-H SourceHanSans-Medium.otf}
\font\test=uprml-h
\test 源ノ角ナントカ。\bye

上手く出力できていることが判る。なお、ちゃんと LaTeX で使用する話は doraTeX さんの記事に書いてある。

これだけでは意味がない

というわけで、zrmakecmap.lua は非常に有用である、といいたいところだが、実はそうでもない。Source Han Sans については、リリースの配布物の中に必要な CMap ファイル(UniSourceHanSansJP-UTF16-H)が含まれている。また一般の場合についても、件の記事をよく読めば解るように、最新の dvipdfmx を使うのであれば、マップ行の CMap 指定を “unicode” にすれば Adobe-Identity-0 のフォントも正常に扱えるのである。

uprml-h unicode SourceHanSans-Medium.otf

この方法では横組みしか対応できないが、しかし今の zrmakecmap も横組みしか対応していないので、特に優位ではない。

実は、このスクリプトを作った目的は「有用なツールを作る」ことではないのであるが、せっかくだから何か有用性を持たせたい。

pTeX できるようにしてみた

というわけで、p(la)TeX 用の CMap を作成できるように拡張した。-j オプションを付けるとこの動作をする。

texlua zrmakecmap.lua -j SourceHanSans-Medium.otf

これで得られたファイル JisSourceHanSansMedium-H を実際に使ってみよう。

% plain pTeX 文書, 文字コードは適当に
\special{pdf:mapline rml JisSourceHanSansMedium-H SourceHanSans-Medium.otf}
\font\test=rml
\test 源ノ角ナントカ。
\bye

※この機能を利用するには、$TEXMF/fonts/cmap/ 以下に(AJ1 の)cid2code.txt ファイルが存在する必要がある。*5

OTC の場合は

zrmakecmap.lua スクリプトOTC(OpenType Collection)ファイルも扱える。例えば、次のように Source Han Sans の(Super でない)OTC ファイルである SourceHanSans-Medium.ttc を入力すると、その中に含まれる全てのフォント(Source Han Sans SC Medium 等)の CMap が作られる。(複数ファイル出力の場合は -o オプションは使えない。)

texlua zrmakecmap.lua SourceHanSans-Medium.ttc

日本語版のフォントである「Source Han Sans Medium」(これは OTC 中でゼロ番目*6にある)の CMap である*7UniSourceHanSansMedium-UTF16-H を使うためのマップ行は次のようになるだろう。

uprml-h UniSourceHanSansMedium-UTF16-H :0:SourceHanSans-Medium.ttc

残念ながら、現状の dvipdfmx ではこの指定を用いて、OTC 版(あるいは Super OTC 版)の Source Han Sans を使うことはできない。最新の dvipdfmx では正常に扱える OTC ファイルもある(例えば、El Capitanヒラギノ角ゴシックの OTC ファイルは扱える)のだが、Source Han Sans はまだ上手くいかないのである。

コレが使えない場合

zrmakecmap の動作は「CID と GID が一致している」ことを前提にしている。そのため、これが成立していない(CID に“欠番”がある)場合は正常に動作しない。例えば、サブセット版(地域版)の OTF である SourceHanSansJP-Medium.otf に対して

texlua zrmakecmap.lua SourceHanSansJP-Medium.otf

を実行して UniSourceHanSansJPMedium-UTF16-H を作成してこれを

uprml-h UniSourceHanSansJPMedium-UTF16-H SourceHanSansJP-Medium.otf

のマップ指定で利用しようとしても失敗する(文字化けが起こる)。これは出力された CMap ファイルが間違っているからであり、実際には SourceHanSansJP-Medium.otf(Source Han Sans JP Medium)の正しい CMap は非サブセットの Source Han Sans (Medium) のものと同一のはずである。*8従って、非サブセット版の OTF の CMap である UniSourceHanSansMedium-UTF16-H を利用した

uprml-h UniSourceHanSansMedium-UTF16-H SourceHanSansJP-Medium.otf

が実は正しい、ということになる。

*1:ただし、luatex や lualatex などの他のコマンド名で実行した場合でも、入力ファイル名の拡張子が .lua である場合は texlua の動作になる。なお、zrmakecmap.lua スクリプトは LuaTeX 特有のモジュールを利用しているので、一般の Lua インタプリタでは動作しない。

*2:この名前は(フォント情報の)ファミリ名を元にして決めている。つまり、このフォントのファミリ名は「Source Han Sans Medium」(「Medium」が付いていることに注意)である。

*3:CMap の命名にはそれなりの慣習があるが、少なくとも dvipdfmx で使う分にはどんな名前でも構わない。

*4:いや、別にゴシック体の TFM(upgbm-h)でもいいけど。

*5:TeX Live や W32TeX ではこの条件は満たされている。

*6:ゼロから数えて。

*7:実はこれは OTF 版のフォントと実質的に等価である。つまり、OTF 版の既定の cmap は日本語になっているのである。

*8:Source Han Sans 全体で共通の CID セットを用いていて、かつ JP サブセットの OTF と非サブセットの OTF(これは既定では日本語用)で cmap は共通であるため。