2012-01-01
OpenTypeレイアウト
あけましておめでとうございます
∩ 2012年 元日
∩∪
∪.| |∩ . 〃ノヽヽ
. | |.| |∪ 从^∀^) <あけましておめでとうございます
. | |.| |.| | ハ∨/^ヽ
(∩∩∩∩) ノ:[三ノ :.'、
(∪∪∪∪) i)、_;|*く; ノ
. |=RSK=| . |!: ::."T~
/≠≠≠\. ハ、___|
1. コンピューターと文字 おさらい
フォントの機能は文字の形をシステムに提供することです。
文字をGIDに直すのは利便性のためです。
2. 合字、字体切り替え、スワッシュ、etc.
フォントは合字を用意したり、アラビア文字の複雑な置き換えを用意したり、グリフ装飾を用意したりできます。
縦書き、ベースライン調整、平均字面、印刷標準字体も用意できます。
これらの機能はOpenTypeレイアウトと呼ばれます。
3. 構成
OpenTypeレイアウトは5つのデータ構造で実現されます。
| タグ | 意味 |
|---|---|
| BASE | ベースライン、平均字面 |
| GDEF | ? |
| GPOS | 位置調整 |
| GSUB | 置き換え |
| JSTF | 行揃え |
4. データ構造
データ構造は木構造を持つかも知れません。
例を上げて説明します。
4.1. Coverageフォーマット
データ構造ではCoverageフォーマットが出現します。IndexとGIDの構造体の配列に展開できます。
4.2. ClassDefフォーマット
データ構造ではClassDefフォーマットが出現します。GIDの集合に展開できます。
5. GSUB:置き換え
GSUBは文字列の置き換えを定義します。正確にはGIDの置き換えを定義します。
5.1. ルックアップタイプ1 Single
1対1の置き換えを定義します。2つのフォーマットが存在します。
フォーマット1はCoverageのGIDにDeltaGlyphIDを足すだけです。
フォーマット2はSubstitute[CoverageのIndex値]が置き換え後のGIDです。
5.2. ルックアップタイプ2 Multiple
1対多の置き換えを定義します。1つのフォーマットが存在します。
5.3. ルックアップタイプ3 Alternate
1対多の置き換えを定義します。1つのフォーマットが存在します。
5.4. ルックアップタイプ4 Ligature
多対1の置き換えを定義します。1つのフォーマットが存在します。
最初の文字に対して、その後ろに続く文字列と置き換えを複数定義することができます。
例)f→[([f,l],ffl),([l],fl),([fi],ffi),([i],fi)]
追記予定
参考資料
2011-12-18
ギコフォントを作ろう!
モナーフォントとは
上の画像のように文字で書かれた絵をアスキーアートといいます。アスキーアートはMS Pゴシックの12ptと決まっています。これがMS明朝だと以下のようになってしまいます。
つまり線が大きくズレてしまうわけですね。このため、MS Pゴシックが存在しない環境でアスキーアートを表示するモナーフォントが開発されました。これはMS Pゴシックとごく似たような文字を含ませたフリーのフォントです*1。下の図はモナーフォントで表示したアスキーアートです。一枚目とそれほど変わりがないと思います。
モナーフォントの問題点
修正: 2011/12/22
- AAを表示するためだけに用意されたフォントなのに二種類のグリフを含むことは容量のムダ。最近はやりのWebFontとして配信する場合も大変手間が掛かります。
- 1ドットのズレも許せない私のような原理主義者にとって、モナーフォントは耐えられない。
仮にMSPゴシックをそのまま違う環境に持ってきたとしても、以下の問題があります。
- Macのような埋め込みビットマップを使用しない環境では、WindowsのMSPゴシックを入れても上手く表示されません。
- AAを表示するためだけに用意されたフォントなのに二種類のグリフを含むことは容量のムダ。
- ライセンス
ギコフォントをつくろう!
修正: 2011/12/22
12ptのビットマップをそのままアウトラインにしたフォントを作る。12pt/24pt/36pt…の倍数でそのとおりに表示されるはず!
著作権・ライセンスの問題
こまけぇこたぁry)
書体の著作権は認められていないのでよしと判断…。ただ、不正競争防止法とかライセンス契約とかは…<(^o^)>
MSGOTHIC.TTC→ 002.TTF
WindowsフォントフォルダにあるMSGOTHIC.TTCを参考資料1のUniteTTCで分割します。
埋め込みビットマップ抜き出し
TTFファイルから埋め込みビットマップを抜き出します。埋め込みビットマップの仕様は参考資料2を参照してください。ここでは自作のpythonフォントライブラリttfを使用して抜き出します。またFontForge用の送り幅設定用テキストも同時に作成しています。
from ttf import ttf from PIL import Image #002.TTF is MS P Gothic File Name. f = open('002.TTF',"rb"); ms_p_gothic = ttf(f); #FontForge script script = open('font_forge_script.txt','w'); cmap = ms_p_gothic.readTable('cmap'); #pratformID = Microsoft(3),encodingID = UCS2(1) ms_encoding=cmap.getSubTable(3,1); GIDMap = ms_encoding.charcode2gindex; for Unicode,GID in GIDMap.items(): eblc = ms_p_gothic.readTable('EBLC'); #12pt/em -(96dpi,1pixel=1dot)-> 16pixel/em ebdt_offset = eblc.getOffset(GID,16,16); #Is there GID in EBDT ? if ebdt_offset is False: continue; ebdt = ms_p_gothic.readTable('EBDT'); #ebdt_offset = point's count array eb_bitmap = ebdt.getGlyph(ebdt_offset[0]); h_ascender = eb_bitmap['bitmapSizeTable']['hori']['ascender']; h_bearing_x= eb_bitmap['metrics']['horiBearingX']; h_bearing_y= eb_bitmap['metrics']['horiBearingY']; h_anvance_width = eb_bitmap['metrics']['horiAdvance']; script.write("Select(" + str(Unicode) + ')\n'); script.write("SetWidth(" + str(h_anvance_width*10) + ')\n'); glyph = eb_bitmap['glyph']; width = eb_bitmap['metrics']['width']; height = eb_bitmap['metrics']['height']; #(255,255,255) is white. img = Image.new("RGB",(16,16),(255,255,255)); for y in range(height): for x in range(width): if glyph[y*width+x] ==1: #(0,0,0) is black. try: img.putpixel((x+h_bearing_x,y+(h_ascender-h_bearing_y)),(0,0,0)); except: print GID,Unicode; large_img=img.resize((16*10,16*10)); large_img.save("glyphs/u" + str('%X' % Unicode) +".bmp"); script.close(); f.close();
このスクリプトを実行すると、uXXX.bmpという画像がglyphsフォルダに作成されます。XXXにunicodeの16進数が入ります。
注意として、元の画像をそのまま1000%拡大したものを保存します。こうしないと、次で説明するpotraceでうまくトレースされません。また「も」の一文字だけ、BearingXが負になるために、正しく画像化されません。この点はFontForgeで手動で修正します。
トレース
自動トレースソフト「potrace」(参考資料3)でビットマップ画像をSVGベクターデータに変換します。以下の一文を書いたバッチファイルを実行することで、glyphsフォルダに同名のSVGファイルが作成されます。
potrace glyphs/*.bmp -s -a 0
FontForge
フォント作成ソフト「FontForge」を用意します。今回はWindows用のバイナリを使用しました(参考資料4)。起動してNewを選んだ後、メニューバーから以下の操作を実行します。
- エンコーディング→エンコーディング変換→ISO 10646-1(Unicode,BMP)を選択
- エレメント→フォント情報→名前→フォント名→「giko」にする
- エレメント→フォント情報→名前→著作権情報→任意に修正
- エレメント→フォント情報→Grid Fitting→65535,NoGridFit,No-Anti-Aliasに設定
- エレメント→フォント情報→一般情報→高さを140、深さ「20」にして、EMSize「160」を確認。(FontForgeは画像の上端をアセンダラインに、下端をディセンダラインにあわせて取り込みます。)
- エレメント→フォント情報→OS/2→その他、Charsets→http://www28095u.sakura.ne.jp/webmozi/fdv/002.TTF/OS2を見て設定する。
以上が終わったら、メニューバーからファイル→取り込み→フォーマットをSVGテンプレート、背景で使用のチェックをオフにして、glyphsフォルダ内の任意のuXXX.svgを選択します。
微調整
取り込んだグリフは全てがベースラインから1unit下にずれていました。メニューバーからファイル→スクリプトを実行を選択して、以下を入力してOKを押します。
SelectAll() Move(0,1)
次に送り幅を設定します。スクリプトを実行から呼び出すボタンを押して、font_forge_script.txtを指定します。OKボタンを押すとグリフに対して送り幅が設定されます。
「も」の修正
x < 0でカットされてしまった部分を手動で付け足します。画像の赤くなっている場所がそうです。
調整
- Ctrl+Aでグリフを全選択して、メニューバーからヒント→ヒントを削除 を選択します。
- Ctrl+Aでグリフを全選択して、エレメント→単純化→単純化 を選択します。
- Ctrl+Aでグリフを全選択して、エレメント→座標を丸める→整数に を選択します。
otf出力
メニューバーからファイル→フォント出力を選択し、OpenType(CFF)、ビットマップフォント無し、Validate Before Savingのチェックボックスをオフにして、保存ボタンを押します。upemが2の乗数になっていないと文句行ってきますが、無視して保存します。
sfd出力
メニューバーからファイル→保存でプロジェクトが保存できます。
確認
出力されたgiko.otfを確認します。
WebFontでテストします
http://www28095u.sakura.ne.jp/gikofont/
ファイル(2011/12/20更新)
sfd: http://www28095u.sakura.ne.jp/gikofont/giko.sfd
・フォント
otf: http://www28095u.sakura.ne.jp/gikofont/giko.otf
ttf: http://www28095u.sakura.ne.jp/gikofont/giko.ttf
eot: http://www28095u.sakura.ne.jp/gikofont/giko.eot
MAC/Linuxインストール用フォント (名前をMSPGothicにした。そのままインスールすればAAが見れる)
otf: http://www28095u.sakura.ne.jp/gikofont/MS-PGothic.otf
ttf: http://www28095u.sakura.ne.jp/gikofont/MS-PGothic.ttf
次回
- グリフがアウトラインのみになったのでWebフォント変換サービスを作ろう その1( ´_ゝ`) - Webと文字で配信できるはず。
- 全てのポイント数でスケーリングが可能になったわけではない。よってhdmxテーブルを規定して、特定のピクセルでの文字幅を定義できるか検討する。
参考資料
2011-11-20
TTF/OTF Reader
自作フォント解析ツール。もともとGAE(GoogleAppEngine)で作っていたけど、さくらVPS512+ngin0.8+apache2.2+mod_wsgi3.3+python2.7.1+django1.3に移植。まだフォントのアップロードができないですが、フォントフォーマットの勉強に良かったら使ってみてください(´・ω・`) safari,Chrome,FireFox,IE9以上で見てください。IE8,Operaは一部の機能が使えません。
2011-10-30
文化がちが〜〜〜う!
- FireFoxとsafariとChromeでJavaScriptの動きがぜんぜん違うとき
- 上にさらにOperaとIEが参戦した時
- Mobileも加わってぐちゃぐちゃに
- PythonとPHPとPerlのLL戦争を見た時
- 上にJavaが出てきたとき
- OpenTypeとTrueTypeとPostScriptの仕様を読んだ時
- AdobeとAppleとMicrosoftでフォントの仕様書が違うとき
- 環境ごとに読み込んだり読み込まなかったりするフォントテーブルがあるとき
- OSごとにフォントのレンダリングがぜんぜん違うとき
- OSのバージョンごとに違う動きをした時
- フォントベンダごとに全然立ち位置が違うのを知ったとき
- 文字集合ごとに字形が微妙に違うとき
- 国ごとに字形がちょびっとづつ違うとき
- IVSをみたとき
- WindowsとMacとLinuxで全然違うとき
- Apacheとnginxでconfの書き方がぜんぜん違うとき
- OSごとに改行コードが違ったとき
- 等々
対立する個々のスタンスは認めたい。AにはAの、BにはBの良さがある。でもA→Bは無理だ。逆も然り。ぜんぜんわからない。文化が違う。戦争する理由がわかった気がした。一種類に限定したほうが(少なくとも当人にとっては)幸せに決まっている。
*1:画像はヒストリエ3巻から借用
2011-10-23
異体字…IVS、フォント、GSUB
世の中には姓名にちょっとでも違う字を使うとうるさく言う奴がいて、そんなこんなでUnicodeに字形切り替えの仕組みが備わった。これをIVSという。特に「ナベ」さんはうるさかったらしく、字形も沢山登録された。
上の図はUnicodeに登録されている異体字リスト(IVD:http://unicode.org/ivd/data/2007-12-14/IVD_Charts.pdf*1)から引っ張ってきた。実は上に挙げたのは一部である。日本人しか使わない、日本人のための表である。ああ素晴らしい( ´∀`)。
こういう規格が何で出てきたのかとか、以下のサイトが詳しかった。
IVSとGSUBはどう違うのか - Mac OS Xの文字コード問題に関するメモ
ともかく、私も日曜フォントプログラマーとして、フォント内部のIVS構造がどうなっているのかを話したい。
仕様
フォントの仕様の部分はここ(Character/Glyph Index Mapping)のFormat 14: Unicode Variation Sequencesに当たる。バイナリのデコンパイル実装は自分で頑張ってください。私が作ったのはこれ*2でChromeブラウザで閲覧することをおすすめする。で、デコンパイルした結果が下。フォントのサンプルにはHanaMinOTPr6N-Regular.otfを使用させていただいた。
http://fontconverter.appspot.com/cmap?platformID=0&encodingID=5&fontname=HanaMinOTPr6N-Regular.otf
見て分かる通り、VS(varSelector)に対して、レコードが幾つといったように、通常とは逆のデータ構造に成っている。defaultUVSOffsetは気にしなくてもいい。nonDefaultUVSOffsetがUnicodeとグリフIDを結びつけているレコードになる。defaultUVSOffsetとnonDefaultUVSOffsetの数値をクリックすると表示を展開するので見て欲しい。
対応表
上のデコンパイル結果を見ても、どのVSがどの表示に対応しているか分からないと思うので、並び替えてリストを作った。ソートされていないのはご愛嬌。
http://fontconverter.appspot.com/cmap2?platformID=0&encodingID=5&fontname=HanaMinOTPr6N-Regular.otf
Unicode#VSとなっている。対応しているグリフIDは右に表示される。クリックしたらグリフに飛ぶ。リストの一番下に37001の定義がある。キャプチャした画像が以下。
http://fontconverter.appspot.com/glyph?fontname=HanaMinOTPr6N-Regular.otf&GID=7947
http://fontconverter.appspot.com/glyph?fontname=HanaMinOTPr6N-Regular.otf&GID=7948
点が有ったり無かったり。極めてどうでもいい、些細な違いのあるグリフがフォント内には別々のIDを振られて格納されている。
GSUB
GSUBとは字形置き換えの仕組みである。IVSの仕組みと何が違うのといわれれば、IVSはUnicodeの仕様、GSUBはOpenTypeFontの仕様である。だからGSUBは字形を置き換える用途ならなんでもありになる。縦書き用のグリフを置き換えたり、アラビア文字の置き換えを定義したり、大体なんでもできる。GSUBの中味を見てみよう。仕様のテーブルの解説はいつかまた。
http://fontconverter.appspot.com/GSUB2?fontname=HanaMinOTPr6N-Regular.otf
featureというのが用途だと思えば良い。14のjp78のmaptableのリンクを見て欲しい。
original GlyphIDが置き換え前のグリフID、substitute GlyphIDが置き換え後のグリフIDである。試しに、index:3の行を見て欲しい。以下キャプチャ。
http://fontconverter.appspot.com/glyph?fontname=HanaMinOTPr6N-Regular.otf&GID=23
http://fontconverter.appspot.com/glyph?fontname=HanaMinOTPr6N-Regular.otf&GID=6210
なんだかゴチャゴチャっとしたグリフに置き換わっているのがお分かりいただけただろうか。こんな感じで言語や用途を指定した上で、使用するグリフをすげ替えてしまうのがGSUBテーブルである。もちろん、今見せたような1対1の置き換えだけではなくて1対多、逆に多対1、特定のグリフ列担った場合に置き換えるなど色々できる。
まとめ
日曜フォントプログラマーとして、IVSとGSUBをフォントフォーマットの観点から語ることが出来た。残念ながら「ナベ」さんだけが異状にうるさい理由は分からなかったが、まあよしとしよう。
お詫び
公開しているプログラム(http://fontconverter.appspot.com/)はバグフィックス中です。エラーコードの表示が出ても許してください☆(ゝω・)vキャピっ


































