ペア・カーニングと従属欧文TFMの作成

合字(リガチャ)

前回の「日本語フォントの従属欧文を使う」の回で書いたように、従属欧文のTFMを作成するには、文字幅情報以外に、合字 (リガチャ) の情報についても考える必要があります。

以下は「find」という英単語を、Timesフォントでそのまま各文字を単に並べたものと、きちんと文字組みした場合です。

文字を単に並べた場合
【リガチャせずに組んだ図】
きちんと文字組みした場合
【リガチャして組んだ図】

このように、英語の組版ではfiという組み合わせが出てきたときには、fとiを単に並べるのではなく、それをくっつけた特別な字形を使って組むという習慣があります。他にも伝統的なドイツ語組版ではchがくっつくとか、言語によっていろいろな習慣があるようです。このようなものを合字 (リガチャ) といいます。

これは、くっついた字の字形がフォント側で用意されていて、それを使うようになっています。例えば、cmr10フォントでは、fiのくっついた字は文字番号0x0cにあります。つまりfでもiでもない別の字として用意されているわけですね。TeXでは、fとiが連続していると、fとiの代わりにfiのくっついた字を使うという風に内部で置き換えて処理します。そして、どの字とどの字が連続したらどの字に置き換えるかの情報はTFM内にあります。

従属欧文の合字

このように、通常の欧文フォントでは、ASCIIコードの空き領域に合字の字形などを含んでいて、その文字番号を指定するとその字形が使えるわけですが、和文フォントの従属欧文では、空き領域には特に字形が割り振られていません。実は、フォント内にfiなどの合字の字形は用意されているのですが、EUCやShift JISの文字コードでは使えないのです。

和文Postscriptフォントは通常Adobe-Japan1-2という文字集合上で字形を定義し、83pv-RKSJ-Hや90ms-RKSJ-HやEUC-Vなどの様々な文字コードからは変換表を通して字形にアクセスできるような仕組みになっています。fiの合字などは83pv-RKSJ-Hには含まれず、Adobe-Japan1-2に含まれている文字です。例えば、Adobe-Japan1-2の文字番号0x0070がfiの合字です。すると、例えばfi (ASCIIコードでは0x66 0x69) の合字の処理としては次のようになります。

■cmr10で「0x66 0x69」が連続
→cmr10の「0x0c」に置き換える。
■Ryumin-heavy-83pv-RKSJ-Hで「0x66 0x69」が連続
→Ryumin-heavy-Adobe-Japan1-2の「0x0070」に置き換える。

しかし、同一フォント内の1バイトコードへの置き換えならTFMで対応可能ですが、別のフォント名の2バイトコードへの置き換えはTFMでは実現できません。これを実現するには、

  1. 「0x66 0x69」の連続をとりあえずTFMで「0x0c」に置き換える。
  2. 「0x0c」を仮想フォント (VF) でAdobe-Japan1-2の「0x0070」に置き換える。

というような二段階の処理が必要です。

各ソフトの対応文字コード

では、こうやって作ったAdobe-Japan1-2の文字データを含むPostscriptファイルを例えばMac版Illustrator 8.0.1に読み込ませてみましょう。はい、見事に文字化けしました。

つまり、Adobe-Japan1-2などという文字コードはShift JISなどとは違い、どんなソフトでも扱えるものではないので、こうして作ったPostscriptファイルをいろんなソフトで扱おうとすると、文字化けの危険を伴うということです。事実上、

以外のことをしようと思ったら、まず文字化けのおそれがあると思っておいた方がいいでしょう。つまり、実質上、出来上がりデータをPDFにする場合以外は、従属欧文の合字はあきらめた方がいいかと思います。PDF以外で合字をやりたければ従属欧文ではなく、一般の欧文フォントを使いましょうということですね。そんなわけで、今のところは合字データなしでTFMを作りたいと思います。

ちなみに、TeXで「---」とハイフンを続けて打つとダッシュになったり、「``」と一重引用符を続けて打つと二重引用符になったりするのは、合字機能を使ったものです。合字データなしのTFMにするということは、従属欧文ではこれらの機能も使えなくなるということです。でも、従属欧文は元々和文の補助ですから、ダッシュを使いたければ「―」、二重引用符を使いたければ「“」という風に、全角文字を使うようにすれば問題はないと思います。

ペア・カーニング

次にTFMに必要な情報として、カーニング量があります。以下は「Tomorrow」という単語をTimesフォントでそのまま各文字を単に並べた場合と、きちんと文字組みした場合です。

文字を単に並べた場合
【カーニングせずに組んだ図】
きちんと文字組みした場合
【カーニングして組んだ図】

そのまま並べた方はTとoの間が他の字間に比べてやけに空いている感じがしますね。別にわざと空けているわけではありません。きっちりくっつけています。下の図はTとoの活字をくっつけて並べたイメージです。

【カーニングの活字イメージの図】

Tの字の右端のラインとoの字の左端のラインをくっつけているのですが、Tの字は元々、文字の下の部分が空いたような字形をしているため、きっちりくっつけてもすき間が空いて見えるのです。この空いている感じをなくすためには、Tとoをくっつけて並べるのではなく、oをTの中にめり込ませて並べなければなりません。

このように、特定の2文字が並んだ場合は字間を調整しないときれいに見えないという組み合わせはYoやLVなど数十組あって、これらの字間を調整する処理をペア・カーニングと言います。どれぐらいめり込ませればきれいに見えるのかはフォントによって違います。TeXでは、この値はTFM内にあって、文字が隣り合ったときに自動的に字間を調整します。TFMを作るなら、この値も必要です。

各フォントの違い

通常の欧文フォントには、どれぐらい字間調整すべきかの値がフォント内に含まれています。DTPソフトはこの値を読みとって自動的に字間調整します。しかし、和文のモリサワフォントなどには、従属欧文のカーニング量のデータを含んでいませんので、DTPソフトでは文字を入力していっただけでは (完全自動では) カーニングができません。(※InDesignとOpenTypeの組み合わせなら設定により自動カーニングできます)

実際、プロが組んだ雑誌などを見ても従属欧文がカーニングされていない部分はよく見かけます。完全自動でできないというのが原因だとは思いますが、私はこれは格好悪いと思います。TeXなら、TFMさえ作っておけば完全自動でカーニングできます。

次の図は、各フォントでカーニングせずに「AVI」「Vol」と打ったものです。

「リュウミンR」
【カーニングしていないリュウミンRの図】
「新ゴL」
【カーニングしていない新ゴLの図】
「太ゴB101」
【カーニングしていない太ゴB101の図】

特にリュウミンの場合がわかりやすいですが、A, V, Iの各文字間が均等に見えず、VI間よりAV間の方がやけに空いているように見えますね。同様にol間よりVo間の方がすき間が空いて見えます (oが少し右に寄っているように見えます)。そして、先ほどの活字イメージを考えると、これは決してわざと空けてるわけではなく、くっつけてこの状態であることもわかると思います。実際、Aの字をぴったり囲む長方形と、Vの字をぴったり囲む長方形を考えると、きちんとくっつけて並べられています。

これを等間隔に見えるように直すのがカーニングです。さらに上記の図をよく見ると、リュウミンではかなり離れている感じがするので、大きくカーニングする必要があり、太ゴなどはあまりカーニングしなくても良さそうといったことがわかります。

カーニング量の求め方

カーニングとは、基本的には各文字間が均等に見えるように調整することです。ならば活字幅などは気にせずに、字形データを元に各文字を構成する線と線の距離を求め、それらが均等になるように配置するという方法が考えられます。(オプティカル・カーニング)

しかし、TeXは基本的に字形データを見ずに組むソフトですので、それをTeXにやらせることはできません。また、距離を均等にといっても、物理的な距離を均等にすれば均等に見えるとも限りません。同じ長さでも目の錯覚でそう見えない例などいくらでもあります。必要なのは物理的に均等に並んでいることではなく、見た目で均等に見えることです。

従って、実際にカーニング量を求める際には、どの文字どうしを隣り合わせたら……と、見た目やバランスを考えて各フォント1文字ずつ値を決めていくべきものでしょう。しかし、欧文の文字幅は元々バラバラなせいか、カーニングの最適値 (というものがあるとして) から少々ずれていてたとしても、そんなに気になりません。また、カーニングの最適値がフォントごとに違うといっても、カーニングのペア自体がそんなに違うわけではありません。例えば、Vo間よりAV間の方を多めに詰める必要があるといった傾向は、どのフォントでもだいたい同じです。

そこで既存のCMフォント等のカーニング量をコピーするという手が考えられます。CMフォントのカーニング量に一定の比率を掛けたものを従属欧文のカーニング量とし、比率はフォントごとに変えるようにするわけです。手抜きといってしまえばそれまでですが、ここは少し手を抜いてもそんなには気にならない部分だと思います。

セリフとサンセリフ

ところで、明朝体は縦線と横線で太さが違っていて、漢字の角の部分や止めの部分が膨らんでいたりといった装飾があります。欧文のTimesフォントなども線の太さに差があり、このような装飾 (セリフ) があります。このようなタイプの書体をセリフ書体と言います。以下の図は「リュウミンL」とTimesで、セリフ部分を示したものです (丸を付けた部分)。和文では「うろこ」という場合もあります。

【リュウミンとTimes共通の特徴であるセリフを示した図】

一方、和文のゴシック体や欧文のHelveticaフォントなどは基本的にすべての線が同じ太さで装飾がありません。このような書体をサンセリフ書体と言います。「サンセリフ」とは「セリフがない」という意味です。もっとも実際は、「中ゴシックBBB」などの和文部分には微妙に装飾があるので厳密にはサンセリフに当たらないと思いますが、概観はほぼサンセリフに近いと言っていいでしょう。

なぜ、いきなりこんな話をしたかというと、セリフ書体はサンセリフ書体に比べて、セリフ部分が飛び出しています。このため、カーニング量が違ってくるのです。実際、隣り合った文字のペアを考えたとき、セリフ書体かサンセリフ書体かでカーニング量が大きく違うペアや、ほとんど変わらないペアがあります。

つまり、先ほどCMフォントなどからカーニング量をコピーすると言いましたが、セリフ書体とサンセリフ書体ではカーニングの傾向が違いますので、これらは別々にコピーした方がいいということになるわけです。例えば明朝体の従属欧文なら、セリフ書体であるcmr10やTimesなどのカーニング量が参考になるでしょうし、ゴシック体の従属欧文ならサンセリフ書体であるcmss10やHelveticaなどのカーニング量が参考になるでしょう。この参考にする書体のカーニング量に比率を掛けてコピー……という方針を考えましょう。

さあ、TFMを作ろう

前に「中ゴシックBBB」の横書きならY-gtbbb-m.tfm、縦書きならT-gtbbb-m.tfmといった風に統一した名前を決めましたが、従属欧文はローマ字ということで、R-gtbbb-m.tfmという風に R- を付けた名前にすることにします。この名前はあくまで例ですが、他のフォントも同様に命名することにします。

TFMを作るには、まずはPLファイルR-gtbbb-m.plを作らないとなりません。前回のcharwidth.psをモリサワフォント搭載のPostscriptプリンタで印刷します。各文字幅データが印刷されます。次に、この文字幅データと先ほど考えたカーニング量からPLファイルを生成するperlスクリプトを作りました。

makeroman.pl (perlスクリプト、EUC)

起動するとPLファイルの名前を聞いてきます。自動的に R- を付けるようにしているので、この場合、「gtbbb-m」と答えて下さい。既にR-gtbbb-m.plが存在するようなら上書きせず終了しますので、PLファイルを新たに作り直したい場合は前のを消しておいて下さい。

次に「セリフ」か「サンセリフ」かを聞いてきますので、この場合、ゴシック体ですから「サンセリフ」を選びます。

次にどの程度のカーニングをするかを聞いてきます。これは、1.0と答えると「cmss10とHelveticaのカーニング量の相乗平均値」になります。0.9ならそれより1割少ないカーニングを行なう意味になります。「セリフ」を選んでいた場合は「cmr10とTimesのカーニング量の相乗平均値」が基準になります。

私の感覚では、だいたい以下のような値を入力すれば、うまくいくと思います。実際は0.1ぐらいずれてもほとんど影響はありません。

●リュウミンR/M/B/H/U
… (セリフ) 1.0
●ヒラギノ明朝W3/6、平成明朝W3
… (セリフ) 0.8
●太ミン
… (セリフ) 0.7
●新ゴL/R/M/B/U、ヒラギノ角ゴW3/6、ヒラギノ丸ゴW4
… (サンセリフ) 1.1
●中ゴシックBBB、じゅん101、ゴシックMB101 B
… (サンセリフ) 1.0
●見出しゴ、平成角ゴシックW5
… (サンセリフ) 0.8
●太ゴ
… (サンセリフ) 0.7

というわけで、今の場合は「中ゴシックBBB」ですから、1.0 と入力します。すると、「33 - ? 」と聞いてくるので、先ほど印刷したデータを見て順番に入力していって下さい。途中で入力間違いに気付いた場合は、「/」(スラッシュ)を入力すると一つ前に戻って聞き直します。さらに「/」を入力すると、さらに前に戻ります。この時、先ほど入力した値も表示されますので、そのままでいい場合は単にReturn (Enter) キーを押し、間違っていれば入力し直して下さい。

94行分すべて入力し終わると、これでいいか聞かれるので、「y」と答えるとPLファイルが作られます。「n」と答えると最初から聞き直してきます。先ほど入力した値も表示され、そのままでいい場合はReturn (Enter) を押すだけになっていますので、一度「n」と答えて見直しをするのもいいでしょう。

PLファイルができたら、コマンドラインから「pltotf R-gtbbb-m」と入力すれば、R-gtbbb-m.plを元にR-gtbbb-m.tfmが作られます。後はこのTFMを使って組版します。psfonts.mapには、

R-gtbbb-m GothicBBB-Medium-83pv-RKSJ-H

と、83pv-RKSJ-Hのフォント名を書いておけば大丈夫ですね。

Shift JISのPostscript作成

なお、和文部分がJISコードで従属欧文がShift JISのPostscriptファイルができるというのは統一感がないと思ったら、すべてShift JISで統一する手もあります。その必要があるのかどうかは別として(笑)。

dvipsはデフォルトではJISコードのPostscriptファイルを作成しますが、「-SJIS」オプションを付けるとShift JISのPostscriptファイルを作成します。もちろん、文字データがShift JISならフォント名もそれに合わせないとなりません。例えば、

H-gtbbb-m GothicBBB-Medium-83pv-RKSJ-H
V-gtbbb-m GothicBBB-Medium-90pv-RKSJ-V
R-gtbbb-m GothicBBB-Medium-83pv-RKSJ-H

このように、psfonts.mapで和文もすべてShift JISのフォントを指定するわけです。もちろん、psfonts.mapにこのように書いた場合は、必ずdvipsに -SJISオプションが必要です。文字コードは必ず合わせないといけません。なお、dvipsの設定ファイルconfig.psに「SJIS」と書き加えておくと、いちいちオプションを付けなくても大丈夫です。

なお、83pvには -V (縦書き用フォント) が存在しません。そのため、ここでは縦書きは90pvにしておきます。90pvなら -Hも -Vも存在します。

ちなみに、83pv-RKSJ-Hと90pv-RKSJ-Vの混ざったPostscriptファイルをMac版Illustrator8.0.1で開き、EPSファイルで保存し直すと、フォントはすべて83pv-RKSJ-H (横書きフォント) に変換されます。では、縦書き部分はどうなるかというと、ちゃんと縦書きで出力できます。実は、83pv-RKSJ-Hには縦書き専用の文字 (縦向きの「ー」や右上にある「、」など) の字形データも含まれていて、これらはMacintosh用機種依存文字という認識になっているんですよね (別の文字番号が割り当てられている)。

したがって、DTPソフトの出力と同じようなPostscriptファイル (83pv-RKSJ-Hのみのファイル) を作りたいと思ったら、縦書きの記号部分はすべてMacintoshの機種依存文字に変換しておかなければならないという話になるんだと思います。まあ、実用上はその必要はないかと思いますが(笑)。

他のフォントでは…

話を元に戻しましょう。次に例えば「新ゴL」従属欧文のTFMを作るなら、まず前回のcharwidth.psを「(ShinGo-Light-83pv-RKSJ-H)」として使い、文字幅情報を得ます。その後、makeroman.plで「shingo-l」と入力。「サンセリフ」を指定して、カーニングの強さは 1.1 などと入力。そして印刷されたデータを94行入力。コマンドラインから「pltotf R-shingo-l」でR-shingo-l.tfmの出来上がりです。psfonts.mapには、

R-shingo-l ShinGo-Light-83pv-RKSJ-H

と書き加えます。……という感じで他のフォントもTFMを作っていけます。なお、「リュウミンL」の従属欧文だけは、次回に問題を指摘し、TFMを作り直します。

使い方

以下のように \font 文で普通に欧文フォントとしてR-gtbbb-mなどを指定すれば問題ありません。

\font\foo=Y-gtbbb-m at 8.5bp
\font\bar=R-gtbbb-m at 8.5bp
\foo\bar
これはtest documentです。

また、以前の「多くの日本語フォントを同時に使う」の回で紹介したLaTeX2eのフォントファミリーの設定を使うなら、その欧文フォント部分に指定するのもいいでしょう。

\DeclareFontShape{JY1}{shingo}{L}{n}{<->s* Y-shingo-l}{}
\DeclareFontShape{JT1}{shingo}{L}{n}{<->s* T-shingo-l}{}
\DeclareFontShape{OT1}{shingo}{L}{n}{<->s* R-shingo-l}{}

上記は抜粋で、他の部分も同様に設定します。従属欧文なら特に倍率を指定することもないでしょう。


渡邉たけし <t-wata@dab.hi-ho.ne.jp>