Hatena::ブログ(Diary)

Webと文字

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

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

2013-05-06

近況報告と今後

近況報告

この一年間、全く関係ない業種で新入社員社畜)をしておりました。


mashabow様のスライドで当ブログを取り上げ戴いたようで、お礼申し上げます。

「TTXによるフォントのぞき基礎」の資料【5/4更新:スライド公開】
http://d.hatena.ne.jp/mashabow/20130502/1367500832

TTXに関して一点、私の方からも気になった点を書かせて戴きます。

随分前になりますが、CFF形式のフォントを変換した際に、グリフパスの表現が固定小数点の場合*1、正常に変換されなかったと記憶しております。


現在は修正されているかも知れませんが、TTXを使われる際には注意したほうがよろしいかと思います。


今後

社畜生活が続くため、記事の更新は一旦停止します。

記事の内容や、サンプルなどは自由に使ってくださって結構です。


以上 ( ´∀`)ノシ

2012-03-22

ギコフォント2

はじめに

以前アスキーアート用のフォント「ギコフォント」を作りました。

ギコフォントを作ろう! - Webと文字


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

f:id:project_the_tower2:20111218091406p:image

今回はその続きです。

専用ページを作った

ギコフォント

f:id:project_the_tower2:20120322105417p:image

他のAAフォントもあった

どちらもwebfontに対応しており、特にKuma_Liteは記号のみではありますが、140kbとすごく小さな容量を実現させています。

ギコフォントも配信することにした

一度目は

  1. @font-faceがサーバーにアクセス
  2. サーバーリファラからURLをとってHTMLを解析
  3. 特定のclass内のテキストを抜き出し
  4. テキストのみのgikofontを作成
  5. URL:gikofontをデータベースに保存
  6. クライアントへ返す

二度目以降は

  1. @font-faceがサーバーにアクセス
  2. データベースから読み出し
  3. クライアントへ返す

page=activeだと、毎回HTMLを解析して、文章(md5)に変更があった場合のみフォントを再作成します。

次回

  • 全てのポイント数でスケーリングが可能になったわけではない。よってhdmxテーブルを規定して、特定のピクセルでの文字幅を定義できるか検討する。

2012-02-20

OpenTypeレイアウトは厳しかった

前回の投稿から間が開いてすいません。想像以上にOpenTypeレイアウトに手間取っております。以下その報告ですが間違っている可能性が十分にあります

フォントだけじゃ無理?

 私はグリフ置き換えがフォント内のOpenTypeレイアウトテーブル内で完結すると思っていたのですが、そうではないようです。

f:id:project_the_tower2:20120220093521p:image

上の画像はArabic Typesetting Sample*1を使用して、ワードパットでアラビア文字による「アラビア語(اللغة العربية)」をキャプチャしたものです。実はこの文字列の各文字は最初からこの形ではありません。

f:id:project_the_tower2:20120220093522p:image

上の画像は同じフォントを用いてOpenOffice.drawで作ったものです*2

  • 1行目は文字ごとにバラバラです。文字コードフォントcmap→アウトラインとすると、この孤立型の形で出てきます。
  • 2行目は単語の語尾に当たる部分()が変化しています。アラビア語は右から左に書くので語尾形です。
  • 3行目は単語の頭に当たる部分()が変化しています。
  • 4行目は単語の真ん中に当たる部分()が変化しています。
  • 2〜4を結合して5行目のアラビア文字表現ができます。

この2〜4行目がフォントのGSUB(グリフ置き換えテーブル)を使って置き換わるはずですが、置き換える場所(どこが語尾で語頭なのか)の情報がフォントには存在しません*3


f:id:project_the_tower2:20120220093524p:image


結合による字形入れ替え方法

 色々調べた結果、Unicode仕様書アラビア文字の結合方法が書かれていることがわかりました。参考資料1に解説PDFが有りましたのでキャプチャを示します。

f:id:project_the_tower2:20120220093525p:image

Unicodeの文字データベース…だと!?

Unicodeの文字データベースUnicode Character Database : UCD)

 Unicodeコンソーシアムは文字一つ一つに対して細かくパラメーターを設定しており、データベースを参考資料2で配布しています。最新バージョンは6.0.0?です。このデータベースを手っ取り早く見たい場合はUCDViewer*4が便利です。

f:id:project_the_tower2:20120220093526p:image

アラビア文字の結合プロパティはjoining propertiesのjt属性に当たります。

[python]UCDから結合プロパティを取り出す

 UCDからプロパティを取り出すプログラムを書きます*5

  1. 参考資料3からucd.all.flat.zipダウンロード
  2. 解凍。7MB→130MB
  3. repertoireだけsqlite3に入れる*6。(http://codepad.org/8qUfWyXS
  4. ucd.dbができあがり。600MBだけど…
  5. インデックス付ける(http://codepad.org/vkMsYmtI
  6. 取り出す関数を書く(http://codepad.org/XMw9QOSw

f:id:project_the_tower2:20120220093527p:image

[python]グリフベースのテキストクラス(読み飛ばしてください)

 グリフ処理のためにグリフベースのテキストクラスを作りました(http://codepad.org/9AVUUpBL)。

テキストの頭と尻に番兵ノードをおいた双方向*7連結リストです。各グリフにはscriptGIDといったプロパティの他にfinishedといった処理済みフラグが存在します。GSUB.feature.lookupのレベルでは一度処理されたグリフはスキップされますが、GSUB.featureのレベルでは処理済みのグリフに対しても続けて処理がかけられます。コード93にあるfinishedフラグ初期化は本来ccmp,isol,fina,medi,initの各substituteの後にも必要です。コード95でfinishedフラグを全てOnにしてアラビア文字に対する処理を終了させます。これによって67のイテレーターはその後、アラビア文字を返しません。

 getIterで特定の条件のみを抽出するイテレーターを返します。これはpythonではジェネレーターで表現できます。getGeneは条件を確定したジェネレーターを返すメソッドです。これはクロージャーで表現できます。条件には*,配列,テキストが使用できます。

[python]結合による字形入れ替え方法の実装

 「結合による字形入れ替え方法」を実装します

for e in self.getIter(script='arab',finished=False):
    cclass = UCD.joining(e.unichar);
    e.feature = 'isol'
    if cclass =='R' and \
       (UCD.joining(e.prev.unichar) in ['D','L','C']):
        e.feature = 'fina';
    if cclass =='D':
        if (UCD.joining(e.prev.unichar) in ['D','L','C']):
            if (UCD.joining(e.next.unichar) in ['D','R','C']):
                e.feature = 'medi';
            else:
                e.feature = 'fina';
        else:
            if (UCD.joining(e.next.unichar) in ['D','R','C']):
                e.feature = 'init';

GSUBを適用する

 結合判定が終わったらGSUBを適用します。アラビア文字に関して必要な処理を以下に示します(参考資料4)。

f:id:project_the_tower2:20120220093528p:image

必須の処理はisol(孤立),init(語頭),medi(中間)fina(語尾),rlig(必須合字)です。aから順番に処理していきます。

置き換わったグリフ

結合判定→GSUBとすることで、正しいGIDを取得することができます。

f:id:project_the_tower2:20120220093529p:image

次回

  • アラビア語の送り幅に関して
  • オンライン上に動くサンプルを用意

参考資料

  1. 多言語組版研究会 Unicodeのアラビア文字、アラビア語のXSL-FOによる組版について
  2. Unicode Character Database
  3. Index of /Public/6.0.0/ucdxml
  4. Microsoft Typography - Developing OpenType Fontsfor Arabic Script (2 of 3):Shaping Engine

*1Microsoft VOLT(http://www.microsoft.com/typography/VOLT.mspx)に同梱されているアラビア語フォント

*2孤立形以外の文字をどうやって出したかですが、互換性のためにUnicodeは割り当てられていますのでそれを使用しています。

*3:前回解説しなかったChainingContextを使うとできるように思いますが、フォントにはSingleテーブルしか入っていませんでした。

*4http://vanillasky-room.cocolog-nifty.com/blog/2011/05/ucdviewer.html この人はすごい(;^ω^)

*5pythonにはunicodedata(http://docs.python.org/library/unicodedata.html)というジャストなパッケージが存在していました…が、目的のプロパティは用意されていませんでした

*6:sql_insert=u"""をsql_insert=u""";にするだけで自動コミットモードになり、生成時間が50秒→一日以上になります。半日ハマった(´・ω・`)

*7:前回解説しませんでしたが、逆から置き換えていくReverseChainingContextものがあるため、双方向にしました

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/testpage.html

f:id:project_the_tower2:20111218091412p:image

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

FontForgeスクリプト

sfd: http://www28095u.sakura.ne.jp/gikofont/file/giko.sfd

フォント

otf: http://www28095u.sakura.ne.jp/gikofont/file/giko.otf

ttf: http://www28095u.sakura.ne.jp/gikofont/file/giko.ttf

WebFont(IE)用フォント

eot: http://www28095u.sakura.ne.jp/gikofont/file/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/file/MS-PGothic.otf

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

次回

フォントの修正 [追記2012/3/30]

修正1

ビットマップが入っていない文字(空白など)が含まれていないため、ズレズレでした。

スクリプトを以下のように修正し、文字幅テキストを作成します。

#out bitmap character script
advance_width = open('width.txt','w');
#…
    if ebdt_offset is False:
        advance_width.write("Select(" + str(Unicode) + ')\n');
        advance_width.write("SetWidth(" + str(hmtx.getMetric(GID)[0]*160/256) + ')\n');
#…

これをFontForgeに読み込ませ、幅のみのグリフを作成します。

修正2

upemを160から1024に変更しました。

修正3

gaspを修正しました

ファイル

FontForgeスクリプト

sfd: http://www28095u.sakura.ne.jp/gikofont/file/giko2.sfd

フォント

otf: http://www28095u.sakura.ne.jp/gikofont/file/giko2.otf

ttf: http://www28095u.sakura.ne.jp/gikofont/file/giko2.ttf

参考資料

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