ちょっとした覚え書き。
GS>/MS-Gothic-90ms-RKSJ-H findfont Loading a TT font from /cygdrive/c/windows/fonts/msgothic.ttc to emulate a CID font MS-Gothic ... Done. GS<1>pstack -dict- GS<1>
GSにしろDistillerにしろ、findfontが指定したフォントを見つけられなくてもデフォルトではエラーになりません。
一生懸命置き換えようとします。
でも指定したフォントがきちんとあるかどうか確かめたい場合もあるわけで。
そういうときはfindfontして/FontName
を調べます。
GS>/MS-Gothic-90ms-RKSJ-H findfont Loading a TT font from /cygdrive/c/windows/fonts/msgothic.ttc to emulate a CID font MS-Gothic ... Done. GS<1>/FontName get == /MS-Gothic-90ms-RKSJ-H GS>/hoge findfont Can't find (or can't open) font file /usr/share/ghostscript/9.06/Resource/Font/hoge. Can't find (or can't open) font file hoge. Querying operating system for font files... Can't find (or can't open) font file /usr/share/ghostscript/9.06/Resource/Font/hoge. Can't find (or can't open) font file hoge. Didn't find this font on the system! Substituting font Courier for hoge. Loading NimbusMonL-Regu font from /usr/share/ghostscript/fonts/n022003l.pfb... 3903192 2482606 2995112 1659037 1 done. GS<1>/FontName get == /Courier GS>
GS>(*) { == } 256 string /Font resourceforall (MS-Gothic-90ms-RKSJ-H) (MS-PMincho-WP-Symbol) (MS-Gothic-78-H) ...
文字列ではなく、オブジェクトが返ってくる(definefontしたような場合か?)もあるらしい。
CIDMap
をきちんと指定すれば使えるようになります。
CIDMap
は同じフォントをGhostscriptでロードして持ってくるのが簡単です。
ASCII85エンコードしてPostscriptファイルに詰め込んでおけばいいでしょう。FlateEncodeすることもできます。
ただし、GhostscriptのCIDMap
は縦書きグリフがきちんと置換されていません。
Distillerではきちんと縦書きが動くので、できれば置換してからコピーしたいところですが。
/MS-Mincho /CIDFont findresource dup length dict copy begin currentdict /FID undef currentdict /UIDBase undef currentdict /UniqueID undef /XUID [ XUID aload pop 0 ] def /CIDFontName /MS-Mincho-Vert def /FontName CIDFontName def /FontType 42 def ・・・ CIDFontName currentdict end definefont pop
XUID
は要素をひとつ増やしています(とりあえず0にしてある)。
FontType
を42にしているのはPLRMにそう書いてあるから(TrueTypeの場合definefontするまではそうしておけと書いてある)。
字間・文字列の描画方向を直すにはCDevProc
を再定義します。
CDevProc
で指定する値はフォント座標系の単位なので、本来はFontMatrix
を参照する必要があります。
しかし、TrueTypeのFontMatrix
は恒等変換になっているのが普通なので、
/CDevProc { pop 10 array astore dup 0 0 put dup 1 -1 put aload pop } bind def
でOKでしょう。
これでちゃんと縦に書けます。
細かいことを言うと書き出し位置が横書きのベースラインの位置になっているので、これも直したい場合はFontMatrix
を適当にいじってください。
縦書きグリフの置換がうまくいかないのはCIDMap
に問題があります。
たとえば、90ms-RKSJ-V
を指定すると、「」
やぁぃぅー
などの
文字はきちんと縦書きグリフのCIDに変換されます。
これをやっているのはCMap
です。
TrueTypeの場合、CIDがさらにTrueTypeフォントのグリフIDに変換されます。
これをやっているのがCIDMap
です。
ややこしいですが。
TrueTypeには文字コードからグリフIDへの変換テーブルが入っていて、Ghostscriptはこれを使ってCIDMap
を作っています(たぶん)。
Unicodeには一部に縦書きグリフ用の文字コード割り当てがあるようですが、showに渡す文字列を縦書き用に変えなければ意味がありません。
縦書き用に変えてもそういう文字コードへのグリフ割り当てがなければ表示できません。
そもそも文字コードがないものは、Ghostscriptは横書きのグリフIDを縦書きにもそのまま使います。
結局、縦書きを指定しても通常は全部横書きグリフでレンダリングされます。
TrueTypeではさらにいろいろなグリフ置換を担当するGSUBというテーブルがあります。
縦横変換もGSUBの中に入っています(kanaスクリプト、JAN言語、vertフィーチャー)。
Ghostscriptはこのテーブルを見ていません。
仕方がないのでcidfmap上で元のフォントの字形集合をIdentity 0
と指定したフォントを作り(CIDがそのままグリフIDとして使われるようになります)、それを読み込んでコピーした上で、元のフォントのCIDMap
をコピーして、さらに縦横グリフを入れ替えます。
cidfmapはこんな感じ。
/MS-Mincho << /CSI [(Japan1) 3] /Path (/cygdrive/c/windows/fonts/msmincho.ttc) /SubfontID 0 /FileType /TrueType >> ; /MS-Mincho-Unity << /CSI [(Identity) 0] /Path (/cygdrive/c/windows/fonts/msmincho.ttc) /SubfontID 0 /FileType /TrueType >> ;
TrueTypeの仕様はMSDNに行けば見つかります。 現在、TrueTypeはOpenType Font(OTF)というフォーマットに含まれているので、MSDNで「OpenType」と検索すればこんなのが見つかるでしょう。 リンクをたどっていくと無料でダウンロードできるISO/IECのサイトへのリンクがあったりします(ISO/IECのドキュメントが無料で手に入るなんてめずらしいんだぞ)。 で、それを見ながら作ったのがコレ。
一部対応してないテーブル形式があるので、動かなくても文句は言わないでください(自分で改造してください・・・OTFの仕様が難解なのでちょっときついかもしれませんが)。 少なくともWin7付属のMS明朝・MSゴシック・メイリオでは動いています。 昔Windows Drawに付いてきた古いDFフォントはGSUBではなく、mortテーブルで縦横置換をしていて、このプログラムでは置換テーブルは出てきません。 このフォントはグリフテーブルの文字コードがシフトJISで、GhostscriptではUnicodeじゃないとIdentityを指定できないので、置換テーブルが取り出せてもダメなんですけどね。 同じDFフォントでも今売っているUnicode TrueTypeフォント(ex: TypeMuseum 3712・・・買ったらしい)は大丈夫です。
コンパイルしてコマンドラインにttc(TrueTypeコレクション、複数のフォント、たいていは等幅とプロポーショナルフォント、を、TrueTypeフォントを集めた形になっているもの)フォントファイルを指定して実行すると、標準出力に
0 beginsubfont 605 beginsubsttable @ 826 18594 ; ... endsubsttable endsubfont
こんな調子で置換テーブルを吐くので、ファイルにリダイレクトして使ってください。
@
と;
にはさまれた一組の数値のうち、前に書いてあるのが横書きグリフのID、後ろに書いてあるのが対応する縦書きグリフのIDです。
@
も;
もPostscriptプログラム内では名前として使えます。
MS明朝の等幅フォントはサブフォント0ですので、
6 dict begin /beginsubfont { /@ { } def /endsubfont { } def 0 eq { /; { def } def /beginsubsttable { dict begin } def /endsubsttable { currentdict end } def } { /; { pop pop } def /beginsubsttable { pop } def /endsubsttable { } def } ifelse } def (msmincho.subst) run end /MS-Mincho-subst exch readonly def
こんな感じにするとサブフォント0の分だけの辞書ができあがります。
セミコロンが見づらいですが。
この辞書はキーが名前ではなく、横書きグリフIDの数値そのものになっています。
実はPostscriptの辞書のキーはどんなオブジェクトでも構いません。
キーをeqオペレータで比較したときにtrue
になれば、その値を返すようになっています。
この場合は横書きのグリフIDをキーとして検索すれば縦書きグリフIDが得られますから、CIDMap
の置換は以下のようにします。
% str cid glyphid <setgid> str /setgid { 2 dict begin /glyphid exch def /cid exch def dup cid 2 mul glyphid 256 idiv put dup cid 2 mul 1 add glyphid 256 mod put end } def % str cid <getgid> str glyphid /getgid { 1 dict begin /cid exch def dup cid 2 mul get 256 mul 1 index cid 2 mul 1 add get add end } bind def /MS-Mincho-Unity /CIDFont findresource dup length dict copy begin /CIDFontName /MS-Mincho-Vert def ・・・ /CIDMap [ /MS-Mincho /CIDFont findresource /CIDMap get 0 get dup length string copy 2 dict begin /i 0 def /gid null def MS-Mincho-subst begin dup length 2 idiv { i getgid /gid exch store currentdict gid known { i currentdict gid get setgid } if /i i 1 add store } repeat end end ] readonly def
MS-Mincho-Unity
が実際に置換を行うフォント、MS-Mincho
がパクり元になります。
できあがりのフォント名はMS-Mincho-Vert
にしてあります。
元のフォントをコピーしてCIDSystemInfo
をIdentity 0
に書き換えてdefinefontしても一応動きますが、コアを吐いたりと不安定になります。
だからと言ってCIDSystemInfo
を書き換えないとCIDMap
の書き換えがうまくいきません(これで相当悩んだ)。
TT_cmapを書き換えるという手もありますが、ps2pdfでPDFにしたときに反映されないようです。
GhostscriptのCIDMap
は配列の中にひとつだけ大きな文字列が入った形をしているので、このコードでもそうなっていることを前提にしています。
で、CIDMap
をコピーしておいて前から順に調べていき、subst辞書を引いて値が見つかれば置換しています。
このプログラムでは置換すべき縦書きグリフIDのある横書きグリフIDはすべて書き換えられてしまいます。
本来は縦書きCIDに対応するグリフIDだけを置き換えるのが正しく、さらにCDevProc
をきちんと書けばふたつのWMode
にもきちんと対応できます。
でも面倒くさいので横書きグリフもろとも入れ替えてしまい、横書きのフリをして縦書きグリフを表示することにします。
CIDFontName currentdict end definefont pop /MS-Mincho-Vert-90ms-RKSJ-H /90ms-RKSJ-H [ /MS-Mincho-Vert ] composefont pop /MS-Mincho-Vert-90ms-RKSJ-H 36 selectfont 72 720 moveto (「縦書きー」) show
メイリオは等幅フォントがありませんが、通常の(メイリオUIではない)フォントの全角部分はおおむね等幅でできているようで、いわゆる半角文字を混ぜなければ見られる程度の縦書きにはなります。
この方法は字形集合をIdentity 0
とした部分だけ、PDF上で文字列のコピーがきちんと動きません。
なるべく文字列が正しくコピーできるようにしたい場合は、縦書きグリフが必要な部分だけIdentity 0
なフォントを使い、他の部分は普通のフォントを使うなどの対象が必要です。
それでもコピーできない場所は残りますが(縦書きの拗音・句読点は全部化けます、当然ですが)。
Distillerの場合はCIDMap
での置換が普通に効くので、GhostscriptからパクったCIDMap
にGSUBによる置換をきちんと施してやれば、90ms-RKSJ-V
を指定すればきちんと縦書きになり、さらにコピーも普通にできるはずです。
文字幅も正しく計算されるので、CDevProc
を置き換えなくても正しい方向に正しい字間でレンダリングされます。
今年は頑張りました。 Acrobatでカレット位置がおかしい以外は実用上差し支えない程度になっています。 PostScriptコードだけで完結していて、Unityフォントも必要ありません。 以下に原理を示します。 実装はがらくた箱に載せる予定です。
PostScriptでの多バイト文字表示は、まず、文字をCMap
でCIDに変換し、フォントのCIDMap
でフォント依存のグリフID(GID)に変換する。
縦書きの場合、CMap
を縦書き用、例えばUniJIS-UTF8-V
にすると、横書きと縦書きでグリフが違う文字は横書きとは異なるCIDにマッピングされる。
フォントドライバではCIDとGIDを1対1でマッピングすればいいように作ってある。
GhostscriptでもCMapはAdobe謹製のものが用いられている。
Resource/CMap
以下のファイルを見ると、一部のファイルを除いてAdobeのCopyrightが書いてあり、その下にBSDライセンスっぽい文言が書かれてるだろう。
CIDMap
の方はフォントドライバが用意することになる。
CIDの一覧(文字集合)はAdobeから公開されてるよ →
The Adobe-Japan1-6 Character Collection
TrueTypeでの多バイト文字表示は、文字コードからGIDへ変換するcmapというテーブルがある。 どの文字コードを使うかはcmapテーブルのヘッダに書いてある。 複数の文字コードをサポートしていることもある。 TrueTypeでの縦書きは、GSUBテーブルにvertフィーチャーがあれば縦書き対応であり、ここに横書きのGIDに対する縦書きのGIDが書いてある。 つまり、文字コード ―(cmap)→ 横書きGID ―(GSUB/vert)→ 縦書きGID という変換をする。 現在、TrueTypeの仕様はOpenTypeの仕様に包含されており、例えばMicrosoftなんかが公開してる → OpenType specification
GhostscriptでTrueTypeを使って多バイト文字表示する場合、文字コードをCMap
でCIDに変換したあと、Decoding
というテーブルを使って一度Unicodeに変換しているようだ。
元がUnicodeなら一度CIDに変換したものをUnicodeに戻していることになる。
その後、TrueTypeのcmapテーブルでGIDに変換してグリフを得ている。
このcmapテーブルは当然 Unicode → GID のものを使う。
つまり、文字コード ―(CMap)→ CID ―(Decoding)→ Unicode ―(cmap)→ GID という流れである。
CMapはPostScriptの、cmapはTrueTypeフォントのテーブル。
How to use Ghostscriptに「Using Unicode True Type fonts」という章があるが、Unicodeじゃないといけないのはこれが理由らしい。
TrueTypeのcmapはフォント辞書にTT_cmap
という名前で含まれており、これを変更すればGIDも変わる。
このパスではCIDMap
は使わない。
2013年版でCIDMap
が効かなかったのはこれが理由らしい。
そして、CIDSystemInfo
をIdentity 0
にするとCIDMap
が直接使われるようになるらしい。
フォント辞書にはsubst_CID_on_WMode
という辞書が含まれていて、これが横書きGIDから縦書きGIDへの変換を担当しているようなのだが、どうもこの機能が中途半端らしく、きちんと縦書きにならないわ、元のフォントをコピーしてCIDSystemInfo
をIdentity 0
に書き換えて使うとコアを吐くわ、ということらしい。
subst_CID_on_WMode
をundefすればコアを吐かなくなることも判明した。
Decoding
やTT_cmap
はGhostscript独自のエントリーで、Acrobat(Reader含む)では使わない。
だから2013年版でTT_cmap
を書き換えてもPDFとして閲覧したときには反映されなかったわけだ。
逆に、AcrobatではCIDMap
による置換が普通に効く。
たとえGhostscriptでPDFを生成した場合であっても、である。
PDFを生成するときにはグリフをレンダリングする必要はない。
グリフをレンダリングするのはPDFを表示するときであって、これをやるのはAcrobatである。
Ghostscriptがフォント辞書さえきちんとPDFに吐いていれば、あとはAcrobatがきちんと表示してくれる。
また、AcrobatはCIDを基にしてクリップボードへのコピーを行うらしく、CIDはCIDSystemInfo
が決まらないとグリフとの対応、つまり文字との対応が決まらない。
日本語ならJapan1
と指定するのだが、GhostscriptでCIDMap
による置換ができるようにIdentity 0
としてしまうと、文字集合が分からなくなってしまうのでコピーができない。
しかし、PDFにしてAcrobatで見る分にはJapan1
を指定してもCIDMap
での置換が普通に効くので、これでコピー問題も解決である。
したがって
subst_CID_on_WMode
をundefする。
CIDSystemInfo
をIdentity 0
に、PDFを生成する場合はフォントのものをそのまま使う。
CIDMap
を使う。
とすると、2013年版のようなUnityフォントは不要になり、GhostscriptでもAcrobatでもきちんと表示できて、さらにAcrobatではコピーもきちんとできるようになる。
次にグリフの入れ替えについてである。 概要は2013年版に書いたとおりである。 スクリプトはkanaの他にhani(CJK Ideographic、直訳すると中日韓表意文字、つまり漢字のこと)もサポートした方がいいかもしれないが、日本語のフォントはだいたいどちらも同じテーブルを指しているようだ。 言語についてはJANが含まれておらず、デフォルト言語を使わなければならないフォントもあった(例: IPAexフォント)。
縦横共用のCIDMap
を作る場合、問題になるのは「横書きのGIDはそのままにしておく」点である。
TrueTypeの縦書きGIDは、横書きGIDから得るようになっている。
したがって、2013年版のようにCIDMap
内にあるGIDを調べ、置換できるなら片っ端から置換するのが簡単なのだが、これだと本来横書きのCIDも縦書きのグリフで描画されてしまう。
縦書きのCIDについてのみ置換したい場合、まずCIDが横書きか縦書きか判断する必要がある。
これが第1の難関。
縦書きだと分かったら、対応する横書きのグリフIDを得なければならない。
これが第2の難関。
さらにややこしくしているのが、横書きと縦書きで異なる文字が同じCIDに割り当てられていることがあり、さらにGSUBで置換したあとのGIDが横書きでも使われる場合があるという点。
UnicodeのU+2190は、UniIJS-UTF32-H
を見るとCID 737に、UniIJS-UTF32-V
を見るとCID 738に変換されることが分かる。
先ほどのAdobe-Japan1 Character Collectionを見ると、横書きでは左向き、縦書きでは上向きの矢印になる。
あれ? と思って横書きでの上向き矢印、UnicodeでU+2191を見ると、UniIJS-UTF32-H
ではCID738で、CID738は縦書きからも横書きからも使われることが分かる。
UniJIS-UTF32
の場合、矢印は以下のようになっている。
文字 | Unicode | UniJIS-UTF32-H | UniJIS-UTF32-V |
---|---|---|---|
← | U+2190 | 737 | 738 |
↑ | U+2191 | 738 | 736 |
→ | U+2192 | 736 | 739 |
↓ | U+2193 | 739 | 737 |
このような例は罫線類にも大量にある。
また、このような置換を行うCMapと行わないCMapがある。
矢印の場合、上に挙げたUnicode系、90ms-RKSJ-V
のようなシフトJIS系は置換される。
EUC-V
などEUC系は置換されない。
他の文字についてもこのようなことがありうる。
調べてないけど。
TrueTypeフォント側のGSUBも普通は上のとおりの対応になっている。
実際にはCID側で置換が起こるので、GSUB側での置換は不要である。
CIDもGIDも置換後の対応は同じはずなので通常は置換しても問題ない。
ところが、MSゴシックなどはGSUBで置換すると、横書きのGIDとは異なる縦書き専用のGIDになる。
実際にakamoz-ttfproc.ps
でVerboseログを吐かせてみると、
<00002190>: vcid=738 hcid=737 hgid=17081 vgid=18838 (orig=17082) <00002191>: vcid=736 hcid=738 hgid=17082 vgid=18839 (orig=17083) <00002192>: vcid=739 hcid=736 hgid=17083 vgid=18840 (orig=17084) <00002193>: vcid=737 hcid=739 hgid=17084 vgid=18841 (orig=17081)
という置換が起きていることが分かる。
おそらくGID 17081とGID 18841は同じグリフなんだろうけれども、もし横書きと縦書きで矢印のグリフが違ったら、CIDMap
を縦書きと横書きで共用できないことになる。
また、このような入れ替え・巡回置換は処理上でも若干注意が必要である。 例えば上の順に処理が進んだとすると、CID 738のGIDがまず18838に書き換えられる。 次にCID 736のGIDを書き換えるのだが、対応する横書きのCIDが738で、このGIDは既に18838に書き換わってしまっているので、GSUBテーブルが引けない。 正しく処理するためには、横書きのCIDからGIDを得るときに書き換え前のテーブルを引かなければならない。
もうひとつ、Unicodeには変な仕様があり、「縦書きのカギカッコ」という文字がある。
普通の「カギカッコ」はU+300Cで、これは横書きなら横書きのカギカッコのCID(686)、縦書きなら縦書きのカギカッコのCID(7911)になる。
一方、「縦書きのカギカッコ」という「文字」は
CJK Compatibility Forms
というグループに入っていて、U+FE41である。
この表を見ると他にも変な文字がいろいろあることが分かるだろう。
CMapを見ると横書きでも縦書きでも縦書きのカギカッコのCIDになっている。
正確には、UniJIS-UTF32-V
はUniJIS-UTF32-H
をベースとして縦書きでCIDが異なるものだけ上書きするような定義になっているが、U+FE41はUniJIS-UTF32-V
で定義されていない。
つまり、UniJIS-UTF32-H
のものがそのまま使われ、CIDは7911になる。
Ghostscriptがこれをレンダリングするとき、CIDを一度Unicodeに戻すが、CID 7911はU+FE41に戻るらしい。 MSゴシックなどはU+FE41に対応するGIDがないため、次善の策としてU+300CのGIDが使われるらしく、横書きのカギカッコが出る。 一方、IPAexフォントはU+FE41に対応するGIDが定義されていて、たとえばIPAex明朝ではGID 7497となっており、U+300CのGID 452をGSUBで縦書きに置換したGIDと同じである。 縦書きのCMapを使った場合、前者はU+300C・U+FE41のどちらでも縦書きのグリフが出ず、後者はどちらでも縦書きのグリフが出る。 逆に、Unicodeで縦書き文字がない文字、たとえば「ー」については、どちらのフォントも全部横書きのグリフが出る。 このせいでGhostscriptでそのまま縦書きしようとするとなんとも中途半端な表示になる。
先ほど、GhostscriptのフォントドライバはレンダリングにCIDMap
を使わない、と書いたが、一応CIDMap
は用意してくれている。
このCIDMap
、縦書き用のCIDについてはどうも縦書き文字を使って生成しているらしく、縦書きカギカッコのCID 7911は、U+FE41をサポートしているIPAexフォントでは縦書きカギカッコのGIDが入っているのに対し、U+FE41をサポートしていないMSゴシックでは横書きカギカッコのGIDになってしまっている。
まあ要するにGhostscriptはGSUBを見ていない、ということである。
最初、縦横共用のグリフについては置換を行わない、という方針で書いていたのだが、Unicodeで縦書き文字があると、縦書き専用と考えられるグリフが縦横共用と判定され、置換の対象から漏れるようになってしまった。 IPAexのように元から正しいグリフが入って入ればよいが、MSゴシックのように縦書き文字に対するグリフがない場合、横書きのまんまという事態が生じる。
かといって共用グリフも置換すると、MSゴシックのようにCIDは縦横共用なのにGIDが別々の場合、横書きのときのCIDMap
が「あやしい」ということになる。
なんつうか、UnicodeとMicrosoftがAdobeの成果を台無しにしている感じである。
このあたりをどうするかは悩ましいところだが、縦書きfixプロシージャを呼んでいるという事は、縦書きしたいのだろうということで、「GSUBにあれば共用だろうがなんだろうが置換」という方針を採ることにした。
CMapとGSUBの考えていることが同じならば、たとえGIDが違ったとしてもCIDが同じである以上、ほぼ同じグリフが出るはずである。
CMapとGSUBが食い違っていた場合はGSUBの考えていることが優先、ということになる。
それで、肝心の第1の難関と第2の難関だが、第1の難関、CIDが横書きか縦書きかを判断するためには、要するにCMapをデコードできればよい。
これは長年悩んでいて、CMapの辞書はImplementation-dependentなのである(PLRM 5.11.4)。
だから、CMapを定義しているリソースファイルを読んで自力でテーブルを構築する必要があるのだが、リソースファイルのありかを簡単に調べる方法が分からなかったのである。
これは実はPostScriptの仕様として用意されていて、リソースのページに書いてあるように、カテゴリ辞書のResourceFileName
を使えばよい。
これはGhostscriptでもDistillerでも使えるはずだ。
ファイルが分かってしまえばこっちのもんで、CIDInit ProcSetのオペレータ(プロシージャ)を定義しなおしてファイルを突っ込んでしまえばよい。
先ほど書いたとおり、CMapは横書きがベースで、縦書きは必要な分だけ置き換えるようになっている。 だから、CMapテーブルができればあとは簡単で、縦書きCMapで置き換えているCIDだけGSUBを引いて置換すればよい。 縦書きCMapさえ指定してもらえば、横書きCMapはusecmapのオペランドとして勝手にくっついてくる。 逆に言うと、そうなってないCMapではちゃんと置換ができない。
第2の難関、対応する横書きGIDを得るには、同じ文字コードで横書きのCMapを引いて横書きのCIDを得、さらにCIDMap
から横書きのGIDを得ればよい。
このとき、先ほど書いたとおり巡回置換に注意する必要がある。
あとはこのGIDでTrueTypeフォントのGSUBテーブルを引けばよい。
最初はCMapの逆引きテーブルを作っていたのだが、CMapテーブルがあるということは、縦書きCMapで置き換えている文字も全部分かるので、文字を列挙して縦書き・横書きのCMapを引くようにしている。
あと残っている作業として、グリフのメトリックを指定する必要がある。
グリフのメトリックはフォント辞書内のMetrics2
辞書か、CDevProc
プロシージャで指定する。
最初は前者で作っていたが、生成に時間がかかるので後者に切り替えた。
具体的にはグリフ座標系原点がグリフの上端中央に動き、進む方向が下になる。
TrueTypeフォント内ではグリフ座標系原点は横書きが基準である。
横方向の原点差分に関しては、CDevProc
では(縦書きであっても)横書きのメトリックが分かるので、その横幅の半分の位置を指定すればよい・・・のだが、Ghostscriptは縦書きを指定すると横書きのメトリック部分が縦書きのメトリックになってしまう。
かといって横書きのフリをすると、グリフ座標原点が動いてくれない(横書きだからね)。
結局、TrueTypeのhmtxテーブルを引くハメになった。
縦方向の原点差分はOS/2テーブル(まさかのOS/2!)のTypoAscenderから得ている。 縦書きのメトリックはvmtxテーブルから得られる。 ここまでやると縦書きもプロポーショナルになる。 hmtxを読むのにhheaを、vmtxを読むのにvheaを読む必要がある。 座標系はFUnitという単位の整数値なので、これをheadテーブルにあるUnitsPerEmで割る必要がある。 無効なGIDを弾き飛ばすのにmaxpテーブルの総グリフ数もいるかもしれない。 あとはTrueType Collectionから目的のサブフォントを見つけるためにnameテーブルが必要である。 必要なテーブルは多分これで全部。
そして、TrueTypeフォントのファイル名もCIDFont
カテゴリリソースのResourceFileName
で分かるため、全部PostScriptコードで書ける。
ページ記述ではリソースファイルを直接読むな、って書いてあるけどね(PLRM 3.9.4)。
最初、フォント辞書のsfnts
を使っていたのだが、GhostscriptではちゃんとTrueTypeフォントの中身が入ってるのに、Distillerではフォントデータのサイズを示すらしい整数値が返ってきて愕然としてしまった。
その後しばらく悩んだのだが、ResourceFileName
でファイル名を取得できることに気づいて解決である。
ファイルがTrueTypeコレクションだった場合、サブフォントを見つける必要がある。
Ghostscriptでcidfmap
を使っていると、CIDFontName
の方はcidfmap
で指定した名前になるので注意。
このため、TrueTypeのnameテーブルとの比較はCIDFontName
とFontName
の両方で行っている。
これで当面の課題は全部解決である。 年末にはとりあえず動くものができていたのだが、いろいろ対応していくうちにこれだけの問題が噴出してしまい、結局こんな時期になってしまった。 ひとつだけ、「Acrobat上でカレットの位置がおかしい」という問題が残っているが。 実装は「がらくた箱」の方に書く予定である。 このページが日本語を読めるGhostscriptの開発者の方の目に留まって、Ghostscriptで何も考えなくても縦書きができるようになる日が来ることを願うばかりである。 願ってないでcontributeしろよ、って話もあるけど。
Copyright (C) 2012-2016 akamoz.jp
$Id: font.htm,v 1.12 2018/02/16 15:38:27 you Exp $