Hatena::ブログ(Diary)

Webと文字

よければ、はてブしてください。( ´∀`) George.Nagaoka@gmail.com

JavaScript IME:海外からブラウザで日本語を変換 新URL 旧URL:
多言語入力ブックマークレット:ブラウザでロシア語、中国語、アラビア語・・・
【軍曹が】携帯電話開発の現状【語る】をAA化した
AAのデータベース
趣味のページ

2012-01-01

OpenTypeレイアウト

あけましておめでとうございます

         謹┃賀┃新┃年┃
   ∩       2012年 元日
   ∩∪
   ∪.| |∩  .   〃ノヽヽ
.   | |.| |∪     从^∀^) <あけましておめでとうございます
.   | |.| |.| |     ハ∨/^ヽ 
  (∩∩∩∩)   ノ:[三ノ :.'、 
  (∪∪∪∪)  i)、_;|*く;  ノ
.    |=RSK=|  .   |!: ::."T~
  /≠≠≠\.    ハ、___|

1. コンピューターと文字 おさらい

f:id:project_the_tower2:20120101212450p:image

フォントの機能は文字の形をシステムに提供することです。

文字をGIDに直すのは利便性のためです。

2. 合字、字体切り替え、スワッシュ、etc.

f:id:project_the_tower2:20120101212451g:image

f:id:project_the_tower2:20120101212455g:image

f:id:project_the_tower2:20120101212452g:image

f:id:project_the_tower2:20120101212453g:image

フォント合字を用意したり、アラビア文字の複雑な置き換えを用意したり、グリフ装飾を用意したりできます。

縦書き、ベースライン調整、平均字面、印刷標準字体も用意できます。

これらの機能はOpenTypeレイアウトと呼ばれます。

3. 構成

OpenTypeレイアウトは5つのデータ構造で実現されます。

タグ意味
BASEベースライン、平均字面
GDEF
GPOS位置調整
GSUB置き換え
JSTF行揃え

4. データ構造

データ構造は木構造を持つかも知れません。

f:id:project_the_tower2:20120101212456p:image

例を上げて説明します。

f:id:project_the_tower2:20120101212458p:image

4.1. Coverageフォーマット

 データ構造ではCoverageフォーマットが出現します。IndexとGIDの構造体の配列に展開できます。

f:id:project_the_tower2:20120101212459p:image

フォーマット1とその例

フォーマット2とその例

4.2. ClassDefフォーマット

 データ構造ではClassDefフォーマットが出現します。GIDの集合に展開できます。

f:id:project_the_tower2:20120101225134p:image

フォーマット1とその例

フォーマット2とその例

5. GSUB:置き換え

 GSUBは文字列の置き換えを定義します。正確にはGIDの置き換えを定義します。


5.1. ルックアップタイプ1 Single

 1対1の置き換えを定義します。2つのフォーマットが存在します。

フォーマット1はCoverageのGIDにDeltaGlyphIDを足すだけです。

f:id:project_the_tower2:20120101225139p:image

フォーマット2はSubstitute[CoverageのIndex値]が置き換え後のGIDです。

f:id:project_the_tower2:20120101225142p:image


5.2. ルックアップタイプ2 Multiple

 1対多の置き換えを定義します。1つのフォーマットが存在します。

f:id:project_the_tower2:20120101225143p:image


5.3. ルックアップタイプ3 Alternate

 1対多の置き換えを定義します。1つのフォーマットが存在します。

f:id:project_the_tower2:20120101225146p:image


5.4. ルックアップタイプ4 Ligature

 多対1の置き換えを定義します。1つのフォーマットが存在します。

最初の文字に対して、その後ろに続く文字列と置き換えを複数定義することができます。

例)f→[([f,l],ffl),([l],fl),([fi],ffi),([i],fi)]

f:id:project_the_tower2:20120101225148p:image

追記予定



参考資料

  1. OpenType フォントの機能

2011-12-18

ギコフォントを作ろう!

モナーフォントとは

f:id:project_the_tower2:20111218091403p:image

上の画像のように文字で書かれた絵をアスキーアートといいます。アスキーアートMS Pゴシックの12ptと決まっています。これがMS明朝だと以下のようになってしまいます。

f:id:project_the_tower2:20111218091404p:image

つまり線が大きくズレてしまうわけですね。このため、MS Pゴシックが存在しない環境でアスキーアートを表示するモナーフォントが開発されました。これはMS Pゴシックとごく似たような文字を含ませたフリーのフォントです*1。下の図はモナーフォントで表示したアスキーアートです。一枚目とそれほど変わりがないと思います。

f:id:project_the_tower2:20111218091405p:image

モナーフォントの問題点

修正: 2011/12/22

 モナーフォントにも問題があります。

  • AAを表示するためだけに用意されたフォントなのに二種類のグリフを含むことは容量のムダ。最近はやりのWebFontとして配信する場合も大変手間が掛かります。
  • 1ドットのズレも許せない私のような原理主義者にとって、モナーフォントは耐えられない。

 仮にMSPゴシックをそのまま違う環境に持ってきたとしても、以下の問題があります。

ギコフォントをつくろう!

修正: 2011/12/22

 12ptのビットマップそのままアウトラインにしたフォントを作る。12pt/24pt/36pt…の倍数でそのとおりに表示されるはず!

f:id:project_the_tower2:20111218091406p:image

著作権ライセンスの問題

こまけぇこたぁ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にunicode16進数が入ります。

f:id:project_the_tower2:20111218091407j:image

 注意として、元の画像をそのまま1000%拡大したものを保存します。こうしないと、次で説明するpotraceでうまくトレースされません。また「」の一文字だけ、BearingXが負になるために、正しく画像化されません。この点はFontForgeで手動で修正します。

トレース

 自動トレースソフト「potrace」(参考資料3)でビットマップ画像をSVGベクターデータに変換します。以下の一文を書いたバッチファイルを実行することで、glyphsフォルダに同名のSVGファイルが作成されます。

potrace glyphs/*.bmp -s -a 0

FontForge

 フォント作成ソフト「FontForge」を用意します。今回はWindows用のバイナリを使用しました(参考資料4)。起動してNewを選んだ後、メニューバーから以下の操作を実行します。

以上が終わったら、メニューバーからファイル→取り込み→フォーマットをSVGテンプレート、背景で使用のチェックをオフにして、glyphsフォルダ内の任意のuXXX.svgを選択します。

f:id:project_the_tower2:20111218091408p:image

微調整

 取り込んだグリフは全てがベースラインから1unit下にずれていました。メニューバーからファイル→スクリプトを実行を選択して、以下を入力してOKを押します。

SelectAll()
Move(0,1)

次に送り幅を設定します。スクリプトを実行から呼び出すボタンを押して、font_forge_script.txtを指定します。OKボタンを押すとグリフに対して送り幅が設定されます。

f:id:project_the_tower2:20111218091409p:image

「も」の修正

f:id:project_the_tower2:20111218091410p:image

x < 0でカットされてしまった部分を手動で付け足します。画像の赤くなっている場所がそうです。

調整

  1. Ctrl+Aでグリフを全選択して、メニューバーからヒント→ヒントを削除 を選択します。
  2. Ctrl+Aでグリフを全選択して、エレメント→単純化→単純化 を選択します。
  3. Ctrl+Aでグリフを全選択して、エレメント→座標を丸める→整数に を選択します。

otf出力

 メニューバーからファイル→フォント出力を選択し、OpenType(CFF)、ビットマップフォント無し、Validate Before Savingのチェックボックスをオフにして、保存ボタンを押します。upemが2の乗数になっていないと文句行ってきますが、無視して保存します。

sfd出力

 メニューバーからファイル→保存でプロジェクトが保存できます。

確認

 出力されたgiko.otfを確認します。

f:id:project_the_tower2:20111218091411p:image

WebFontでテストします

http://www28095u.sakura.ne.jp/gikofont/

f:id:project_the_tower2:20111218091412p:image

ファイル(2011/12/20更新)

FontForgeスクリプト

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

WebFont(IE)用フォント

eot: http://www28095u.sakura.ne.jp/gikofont/giko.eot

MAC/Linuxインストール用フォント (名前をMSPGothicにした。そのままインスールすればAAが見れる)

f:id:project_the_tower2:20111220095005p:image:medium

f:id:project_the_tower2:20111220095006p:image:medium

otf: http://www28095u.sakura.ne.jp/gikofont/MS-PGothic.otf

ttf: http://www28095u.sakura.ne.jp/gikofont/MS-PGothic.ttf

次回

参考資料

  1. UniteTTC
  2. TrueTypeフォントのフォーマットを調べる その22 - Webと文字
  3. potraceをjavascriptに移植した - Webと文字
  4. unofficial fontforge-mingw

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は一部の機能が使えません。

旧:http://fontconverter.appspot.com/

新:http://www28095u.sakura.ne.jp/webmozi/fdv/

2011-10-30

文化がちが〜〜〜う!

f:id:project_the_tower2:20111030192346p:image*1

  • 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という。特に「ナベ」さんはうるさかったらしく、字形も沢山登録された。

f:id:project_the_tower2:20111023111848p:image

上の図はUnicodeに登録されている異体字リスト(IVD:http://unicode.org/ivd/data/2007-12-14/IVD_Charts.pdf*1)から引っ張ってきた。実は上に挙げたのは一部である。日本人しか使わない、日本人のための表である。ああ素晴らしい( ´∀`)。


 こういう規格が何で出てきたのかとか、以下のサイトが詳しかった。

  IVSとフォントの関係 - ちくちく日記

  IVSとGSUBはどう違うのか - Mac OS Xの文字コード問題に関するメモ

ともかく、私も日曜フォントプログラマーとして、フォント内部のIVS構造がどうなっているのかを話したい。


仕様

 フォントの仕様の部分はここ(Character/Glyph Index Mapping)のFormat 14: Unicode Variation Sequencesに当たる。バイナリデコンパイル実装は自分で頑張ってください。私が作ったのはこれ*2Chromeブラウザで閲覧することをおすすめする。で、デコンパイルした結果が下。フォントのサンプルにはHanaMinOTPr6N-Regular.otfを使用させていただいた。

f:id:project_the_tower2:20111023111849p:image

http://fontconverter.appspot.com/cmap?platformID=0&encodingID=5&fontname=HanaMinOTPr6N-Regular.otf


見て分かる通り、VS(varSelector)に対して、レコードが幾つといったように、通常とは逆のデータ構造に成っている。defaultUVSOffsetは気にしなくてもいい。nonDefaultUVSOffsetがUnicodeとグリフIDを結びつけているレコードになる。defaultUVSOffsetとnonDefaultUVSOffsetの数値をクリックすると表示を展開するので見て欲しい。

対応表

 上のデコンパイル結果を見ても、どのVSがどの表示に対応しているか分からないと思うので、並び替えてリストを作った。ソートされていないのはご愛嬌。

f:id:project_the_tower2:20111023111850p:image

http://fontconverter.appspot.com/cmap2?platformID=0&encodingID=5&fontname=HanaMinOTPr6N-Regular.otf


Unicode#VSとなっている。対応しているグリフIDは右に表示される。クリックしたらグリフに飛ぶ。リストの一番下に37001の定義がある。キャプチャした画像が以下。

f:id:project_the_tower2:20111023111852p:image

http://fontconverter.appspot.com/glyph?fontname=HanaMinOTPr6N-Regular.otf&GID=7947

f:id:project_the_tower2:20111023111851p:image

http://fontconverter.appspot.com/glyph?fontname=HanaMinOTPr6N-Regular.otf&GID=7948


点が有ったり無かったり。極めてどうでもいい、些細な違いのあるグリフがフォント内には別々のIDを振られて格納されている。

GSUB

GSUBとは字形置き換えの仕組みである。IVSの仕組みと何が違うのといわれれば、IVSUnicodeの仕様、GSUBはOpenTypeFontの仕様である。だからGSUBは字形を置き換える用途ならなんでもありになる。縦書き用のグリフを置き換えたり、アラビア文字の置き換えを定義したり、大体なんでもできる。GSUBの中味を見てみよう。仕様のテーブルの解説はいつかまた。

f:id:project_the_tower2:20111023111853p:image

http://fontconverter.appspot.com/GSUB2?fontname=HanaMinOTPr6N-Regular.otf


featureというのが用途だと思えば良い。14のjp78のmaptableのリンクを見て欲しい。

f:id:project_the_tower2:20111023111854p:image

http://fontconverter.appspot.com/GSUB3?subtableindex=0&lookupindex=4&fontname=HanaMinOTPr6N-Regular.otf


original GlyphIDが置き換え前のグリフID、substitute GlyphIDが置き換え後のグリフIDである。試しに、index:3の行を見て欲しい。以下キャプチャ。

f:id:project_the_tower2:20111023111855p:image

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キャピっ