フォントサイズをドットで指定する
概要
ゲームプログラマっぽいことをやっていると、デザイナさんから「フォントを○○x○○ドットで出したいじゃごら」なんてことを言われます.
一昔前まではH/Wの制限から"英数字 + 記号 + ひらがな + カタカナ"の文字数で済んでいたんで、「それじゃ、○○x○○ドットのビットマップ画像を
つくってください.そっから16x16ドットの矩形を切り出すんで適当に書いてくれりゃいいよ」なんて言っておけば良かったんですけど、昨今じゃ"+ 欧州文字 + 漢字"
なんてのは当たり前で、ひどけりゃ"+ 中国圏文字"なんてことにもなったりします.
ここまで文字数が多くなってくると、デザイナに手で一定の枠に収めてねっていうのも明らかに無駄ですし、windowsフォントは基本的にポイント指定で
出力する必要があるからドット数なんてよく分からないしと...
ちっちゃいことですが、ゲームプログラマたるもの「デザイナ(会社)指定のフォントを指定されたドット数で出力する」ってことは重要スキルなのです.
とはいえ、ドット単位でで生きてきたゲーム屋さんにとっては、『ポイント』なんて言われてもいまいちピンとこないので、ここいらでフォントサイズについて復習しておきましょう.
基礎知識
フォントサイズの話をする時に、覚えておく必要がある単位系を以下に挙げる.
- point
- dpi(dot per inch)
- em
まず、フォントを指定するときのポイントだが、
1ポイント = 1/72 インチ
と決められている.
なんでこんな中途半端な長さになっているのかってことは、なにか深い歴史的な経緯があるんだろうってぐらいの理解でよい.
次に、dpi(dot per inch) だがこれは、ディスプレイの表示設定に利用される値だ.
これは、「ディスプレイ表示時に、1インチの中にどのぐらいのドットが詰まっているか?」という値.
フォントのサイズはポイントで指定するので、それをドット数に直すためには「1インチって何ドット?」ってことを考えればよいのだ.
この値は環境によって異なり、
例えば、windows xp では、
[画面のプロパティ] - [設定]タブ - [詳細設定] - "DPI設定"
から変更できる.
ちなみに、windows = 96dpi / max = 72dpi が標準らしい.
最後は、emサイズ.
これは、フォント標準の大きさを基準(=1)とした時のサイズ指定に利用する.
web屋さんなんかにはおなじみの単位系らしいけれども、フォントサイズをドットで指定するためには*必要ない*
"フォントサイズ"なんかでググると"emサイズ"の説明なんかが出てくるけど、今回の用途に限って言えば単なる雑音にすぎない.
(Windows API の)CreateFont を利用して指定ドットのフォントを出力する
基礎知識が理解できていれば、指定ドットのフォントを出力することに問題は無いだろう.
つまり
${フォントのポイント数} × ${利用ディスプレイのDPI} ÷ 72 = ${フォント表示のドット数(高さ)}
ってことだ.
Windows SDK の CreateFont のドキュメントには次のように書かれている.
HFONT CreateFont( int nHeight, // フォントの高さ int nWidth, // 平均文字幅 int nEscapement, // 文字送り方向の角度 int nOrientation, // ベースラインの角度 int fnWeight, // フォントの太さ DWORD fdwItalic, // 斜体にするかどうか DWORD fdwUnderline, // 下線を付けるかどうか DWORD fdwStrikeOut, // 取り消し線を付けるかどうか DWORD fdwCharSet, // 文字セットの識別子 DWORD fdwOutputPrecision, // 出力精度 DWORD fdwClipPrecision, // クリッピング精度 DWORD fdwQuality, // 出力品質 DWORD fdwPitchAndFamily, // ピッチとファミリ LPCTSTR lpszFace // フォント名 );
nHeight フォントの文字セルまたは文字の高さを論理単位で指定します。 文字の高さ(em height としても知られている)とは、文字セルの高さから内部レディング(アクセント記号などのためのスペース)の高さを引いたものです。 nWidth フォントの平均文字幅を論理単位で指定します。 0 を指定すると、条件に最も近い値が選択されます。 条件に最も近い値は、利用可能な各フォントの現在のデバイスでの縦横比とデジタル化された縦横比の差の絶対値を比較することにより決定されます。
ここで書かれている論理単位とは、ずばり基礎知識で説明した"ポイント"となる.
文字幅が"平均文字幅"とか、煮え切らない書き方をしているのは、プロポーショナルフォントがあるから.
注意点
以上の説明で、必要なドット数のフォントを出力することができる.
あとは、適当な大きさを確保したビットマップになり、自由にラスタライズしてあげて、textureとして描画するも良し、自前でラスタライズするも良しって感じだが注意点が3点ほどある.
注意点 : ポイント -> ドット の変換では、小数が含まれる可能性がある
ポイントが、1/72インチ等という中途半端な数値なので、利用するdpiによっては端数(= 小数)が含まれる可能性がある.
幸い(?)、フォントのドット数はポイントとdpiによって決まるので、うまいこと端数がでないようなdpi設定を行いラスタライズを行ことも検討の余地がある.
mac では、標準で72dpiらしいのでこういった問題は起きないんじゃないかと思う.(すばらしい:p)
注意点 : 直接指定ドットで出力すると画像品質が悪い
(ゲーム屋の)デザイナさんってのは変な所にこだわりがある.
彼(彼女)たちの興味は、「なるべく少ないドット数で以下にきれいに表示することができるか」なのだ.
(あ、当然ユーザもきれいなフォントは好きだよね)
しかし、デザイナ指定のドット数でラスタライズした画像をそのまま利用すると「これじゃ汚い」って言われてしまう.
作業する、プログラマに取ってみれば正直どうでも良いことなんで「じゃ、全部おまえが打てよ」って言いたくなるところだけれども、そこをぐっとこらえて2倍表示の画像を渡してあげよう.
一手間増えるけど、ご自慢の PhotoShop なんかをつかって好きなように加工を行ってもらえるはずだ.
(そして、ユーザもきれいなフォントに満足するはずだ)
注意点 : Windows API では、unicode描画とSJIS描画で結果(=サイズ)に違いがある
普段は余り意識しなくて良いが、WindowsAPIの CreateFont には、SJIS版のCreateFont とUnicode版のCreateFontWってのがある.
一部フォントでは、CreateFont で出力した結果と、CreateFontW で出力した結果が異なる.
恐らくドット数に変換するときに端数が生まれるような指定の場合に起きるのでは無いかと考えてるが詳細は不明.
事実、マスターアップ近辺でフォントの再出力を行った際に、SJIS指定とUNICODE指定を間違えて出力した結果、文字列がレイアウトに収まらなくて焦ったってことが合ったので注意して置いた方が良い.
まとめ
${フォントのポイント数} × ${利用ディスプレイのDPI} ÷ 72 = ${フォント表示のドット数(高さ)}
- (Win32APIの)CreateFont は、ポイントで指定する
- 1ポイント = 1/72インチ
- DPI(dot per inch)は、画面設定によって異なる
- 標準的な画面設定では、96dpi
- 指定ドットぴったりのフォントを出力するのは本質的に無理がある
- 等倍で出力すると画像品質が悪いのでなんとかする