フォント TrueType 構造解析のソースを表示
新しいページはコチラ
移動:
案内
,
検索
[[フォント]]に戻る。 == 概要 == 仕様書はAppleのホームページに掲載されています。この記事で頑張って読みこみたいと思います。 [https://developer.apple.com/fonts/TrueType-Reference-Manual/ https://developer.apple.com/fonts/TrueType-Reference-Manual/] プログラムを使ってフォント構造をなんらかの方法で処理して理解を助けるようなものを作りたいと思います。できればPDFでグリフ番号も取得しつつ、フォントが埋め込めるくらいまではいきたい。 まずは、FreeTypeが動かせる環境を構築します。そうすると、カラー絵文字処理用のlibpngもいるんだそうな。ということはその圧縮メカニズムを司るzlibもいるんだって。というわけで [[FreeTypeをコンパイル]]にその道中どんなこと作業が必要なのかをまとめます。 [[FreeTypeを使う]]で基本的な操作から、ちょっとした使い方くらいをやってみます。 だいぶと逸れましたが、目的を達成しようと思うと、やっぱりFontファイルの構造を理解しないと駄目ですね。アップルのページを見ながら考えてみます。せっかくなので、C++でフォントのImpact.ttfのバイナリファイルを読み込んで、プログラムによって分解しながら解析してみようと思います。まずはヘッダー情報とテーブルの配置情報が上の方に詰まってるみたいなので、読み込んでみようと思います。理解した情報をテキストに吐き出すということをやってみます。途中、簡易freetypeみたいなことをして遊ぶことを目的にやっていけば、自分でフォントを描画するsvgファイルを作ってみたりできて楽しそう。サブセットを作るための礎を築くことが出来そうな気がしています。ちょっと時間かかりそうだな。もっと若い時に頑張ってみればよかったかも。 力技のプログラムで分解します。カッコいいクラスとかは作る気が無いです。よっぽど繰り返し同じようなプログラムを書いてるなこれって思ったら、なんかやるかもしれないですけど。例外処理とかやる気なし。エラーが出始めても見返せないくらいの奴にしてやりますよ。 === '''構造''' === ttfファイルの構造を以下に示します。 全体としては、ヘッダ部 12byte と TAGと呼ばれる4文字のコードに意味付けがされていて、TAGとその内容という構成が可変長でファイル全体のほとんどを占めます。とくに文字の形に関する情報を持つglyfというタグが容量が大きくなります。ヘッダ部につづいて、それぞれのTAGテーブルがどこに配置されているかを示した情報が1つのTAGあたり16Byteで位置情報を記載しています。これをTAGテーブル部と呼びます。そのあとにそれぞれのタグの値に対応するテーブル部とよばれる大きい容量の領域が続きます。TAGには、フォントファイル内で必ず定義されるべきものと、オプションのものがあります。またフォントファイルの形式毎にも必須となるTAGの違いがあります。OpenTypeフォントのotfやそのコレクションファイルである。otcファイルも一部のTAG情報が独立しているもののほとんど同じような構造になっています。TrueTypeと同じ意味を持っているTAGもあります。TrueTypeのコレクションであるttcもttcだけが扱うTAGがあります。 '''■ヘッダ部(ファイル先頭から12Byte固定 アドレス0x0000 0000 ~ 0x0000000b)''' <table style="width: 100%; text-align: left; border-collapse: collapse; border-spacing: 0;"> <tr style=" background: #778ca3; border-right: solid 1px #778ca3; color: #ffffff;"> <th style="width: 50px;">バイト数</th> <th style="width: 140px;">型</th> <th style="width: 150px;">名前</th> <th>説明</th> </tr> <tr> <td>4</td> <td>unsigned int</td> <td>sfntVersion</td> <td>ttf outline 0x00010000</td> </tr> <tr style=" background: #eeeeee;"> <td>2</td> <td>unsigned short</td> <td>numTables</td> <td>TAGテーブル数</td> </tr> <tr> <td>2</td> <td>unsigned short</td> <td>searchRange</td> <td>TAGテーブル数から決定</td> </tr> <tr style=" background: #eeeeee;"> <td>2</td> <td>unsigned short</td> <td>entrySelector</td> <td>TAGテーブル数から決定</td> </tr> <tr> <td>2</td> <td>unsigned short</td> <td>rangeShift</td> <td>TAGテーブル数から決定</td> </tr> </table> entrySelectorはTAG テーブル数が 16(0x10) 以下なら 3。17(0x11) 以上 32(0x20)以下なら4。33(0x21) 以上 64((0x40))以下なら5。の、ように2^n<=TAGテーブル数となるようなnの最大値がentrySelectorです。 searchRangeは 16 * 2^(entrySelector)という値です。 rangeShiftは16 * TAGテーブル数 - entrySelector という値です。 TAGテーブル数から計算できるこれらの値は、よくわからない意味不明の操作をしているように感じますが、TAGテーブルの範囲を計算するために必要となるような値になっています。無くても原理がわかっていれば、再度計算できますけど、また計算するという時間を減らすために備わっていると考えてよいでしょう。なんどもなんども、読み込むかもしれませんので、計算量の節約に役立つのかもしれません。上記の値にヘッダ部自体が使う12byteをふくめると最初のテーブルへのoffsetが求まります。 '''■TAGテーブル部 (TAG数*16Byteの可変長)''' この部分にフォントファイルで使われるTAGとそのテーブルの位置とテーブルの長さとチェックサムと呼ばれる誤り検知のための符号が記述されます。 <table style="width: 100%; text-align: left; border-collapse: collapse; border-spacing: 0;"> <tr style=" background: #778ca3; border-right: solid 1px #778ca3; color: #ffffff;"> <th style="width: 50px;">バイト数</th> <th style="width: 140px;">型</th> <th style="width: 150px;">名前</th> <th>説明</th> </tr> <tr> <td>4</td> <td>char array[4]</td> <td>tag</td> <td>ASCII code4文字からなるtag名</td> </tr> <tr style=" background: #eeeeee;"> <td>4</td> <td>unsigned int</td> <td>checkSum</td> <td>誤り検出符号</td> </tr> <tr> <td>4</td> <td>unsigned int</td> <td>offset</td> <td>当該tagの始まるポジション</td> </tr> <tr style=" background: #eeeeee;"> <td>4</td> <td>unsigned int</td> <td>length</td> <td>長さ</td> </tr> </table> 例えばWindowsのImpactというフォントだと以下のようなTAGテーブルになっています。見やすいようにTAGテーブルのポジションの値で昇順にしました。あとCheckSumは実際に計算した値も記載しています。もちろんtableに書かれていた値と計算した値は一致しています。 <table style = "width: 100 ; text-align: left; border-collapse: collapse; border-spacing: 0; "> <tr style = " background: #778ca3; border-right: solid 1px #778ca3; color: #ffffff; "> <th style = "width: 100px; ">TAG code</th> <th style = "width: 100px; ">Check sum</th> <th style = "width: 100px; ">Check sum(calc)</th> <th style = "width: 100px; ">Offset</th> <th>Length</th> <tr > <td>head</td> <td>e4e92bf5</td> <td>e4e92bf5</td> <td>0000017c</td> <td>00000036</td> </tr> <tr style=" background: #eeeeee;"> <td>hhea</td> <td>125a0ce1</td> <td>125a0ce1</td> <td>000001b4</td> <td>00000024</td> </tr> <tr > <td>maxp</td> <td>0837030e</td> <td>0837030e</td> <td>000001d8</td> <td>00000020</td> </tr> <tr style=" background: #eeeeee;"> <td>OS/2</td> <td>785c754a</td> <td>785c754a</td> <td>000001f8</td> <td>00000060</td> </tr> <tr > <td>hmtx</td> <td>fea2e775</td> <td>fea2e775</td> <td>00000258</td> <td>00000fec</td> </tr> <tr style=" background: #eeeeee;"> <td>LTSH</td> <td>f1306fc0</td> <td>f1306fc0</td> <td>00001244</td> <td>000003ff</td> </tr> <tr > <td>VDMX</td> <td>6959818c</td> <td>6959818c</td> <td>00001644</td> <td>00001194</td> </tr> <tr style=" background: #eeeeee;"> <td>hdmx</td> <td>1dd7c845</td> <td>1dd7c845</td> <td>000027d8</td> <td>00005408</td> </tr> <tr > <td>cmap</td> <td>089aa4b6</td> <td>089aa4b6</td> <td>00007be0</td> <td>00000672</td> </tr> <tr style=" background: #eeeeee;"> <td>fpgm</td> <td>c7712c46</td> <td>c7712c46</td> <td>00008254</td> <td>00000764</td> </tr> <tr > <td>prep</td> <td>32e8b0c7</td> <td>32e8b0c7</td> <td>000089b8</td> <td>00000855</td> </tr> <tr style=" background: #eeeeee;"> <td>cvt </td> <td>d595b7a9</td> <td>d595b7a9</td> <td>00009210</td> <td>00000620</td> </tr> <tr > <td>loca</td> <td>03dc4364</td> <td>03dc4364</td> <td>00009830</td> <td>00000ff0</td> </tr> <tr style=" background: #eeeeee;"> <td>glyf</td> <td>550e4c1b</td> <td>550e4c1b</td> <td>0000a820</td> <td>00022720</td> </tr> <tr > <td>kern</td> <td>bfcec4b5</td> <td>bfcec4b5</td> <td>0002cf40</td> <td>00000b8e</td> </tr> <tr style=" background: #eeeeee;"> <td>name</td> <td>28de000e</td> <td>28de000e</td> <td>0002dad0</td> <td>00000ba1</td> </tr> <tr > <td>post</td> <td>ff360066</td> <td>ff360066</td> <td>0002e674</td> <td>00000020</td> </tr> <tr style=" background: #eeeeee;"> <td>gasp</td> <td>001d0021</td> <td>001d0021</td> <td>0002e694</td> <td>00000010</td> </tr> <tr > <td>DSIG</td> <td>771dbaee</td> <td>771dbaee</td> <td>0002e6a4</td> <td>00001dc4</td> </tr> <tr style=" background: #eeeeee;"> <td>GDEF</td> <td>00260400</td> <td>00260400</td> <td>00030468</td> <td>0000001e</td> </tr> <tr > <td>GPOS</td> <td>662a22e1</td> <td>662a22e1</td> <td>00030488</td> <td>00000f12</td> </tr> <tr style=" background: #eeeeee;"> <td>GSUB</td> <td>35d8e622</td> <td>35d8e622</td> <td>0003139c</td> <td>000013da</td> </tr> <tr > <td>meta</td> <td>1aa59251</td> <td>1aa59251</td> <td>00032778</td> <td>00000048</td> </tr> </table> 各tagテーブルの本体テーブルは4の倍数のバイト数の長さになるように調整されていて、実際の長さがLengthですが、Lengthが4の倍数になっていない場合は、そうなるように各byte値が00値で埋められます。 このような構造なので、フォントファイル自体は4の倍数のバイト数になっています。ファイルの先頭から4byteづつ読み込んで、4byteをunsigned int値として、足し算を繰り返す操作によって、チェックサムが計算できます。フォントファイル自体のチェックサムは全てのフォントファイルで0xB1B0AFBAになります。これは必須tagのheadのadjustment CheckSumという値で0xB1B0AFBAになるように調整されています。adjustment CheckSumはheadの3番目の4byteの値です。したがって(adjustment CheckSumを除いたフォントファイル全てのCheckSum)+(必須tagのheadのadjustment CheckSum) = 0xB1B0AFBA となります。テーブルごとのチェックサムはテーブルのオフセットポジションから、次のテーブルまでを足し算をした値です。チェックサムの計算を繰り返すと、unsigned intの4byteという容量からはなんども桁あふれが発生しますが、どんどん切り捨てて計算を繰り返します。tag名がheadのテーブルだけはadjustment CheckSumを無視したチェックサムを求めます。 adjustment CheckSumはフォントファイルに変更が発生した場合は計算しなおす必要がある値です。変更が発生したテーブルのチェックサムも変更が必要です。 '''■テーブル部 (可変長)''' ==== head ==== headテーブルは固定長(0x3c Byte)です。 IMPACT.ttfの例は以下のとおりです。 <table style = "width: 100 ; text-align: left; border-collapse: collapse; border-spacing: 0; "> <tr style = " background: #778ca3; border-right: solid 1px #778ca3; color: #ffffff; "> <th style = "width: 100px; ">Name</th> <th>Value</th> </tr> <tr style = " background: #eeeeee;"> <td>MajorVersion</td> <td>1</td> </tr> <tr> <td>MinorVersion</td> <td>0</td> </tr> <tr style = " background: #eeeeee;"> <td>FixedfontRevision</td> <td>5.11</td> </tr> <tr> <td>checkSumAdjustment</td> <td>0x9932de9a</td> </tr> <tr style = " background: #eeeeee;"> <td>magicNumber</td> <td>0x5f0f3cf5</td> </tr> <tr> <td>flags</td> <td>0x001b</td> </tr> <tr style = " background: #eeeeee;"> <td>unitsPerEm</td> <td>2048</td> </tr> <tr> <td>CreateDate</td> <td>1992/07/22 17:04:10</td> </tr> <tr style = " background: #eeeeee;"> <td>ModifyDate</td> <td>2017/03/03 19:59:44</td> </tr> <tr> <td>xMin</td> <td>-265</td> </tr> <tr style = " background: #eeeeee;"> <td>yMin</td> <td>-677</td> </tr> <tr> <td>xMax</td> <td>2894</td> </tr> <tr style = " background: #eeeeee;"> <td>yMax</td> <td>2392</td> </tr> <tr> <td>macStyle</td> <td>0</td> </tr> <tr style = " background: #eeeeee;"> <td>lowestRecPPEM</td> <td>9</td> </tr> <tr> <td>fontDirectionHint</td> <td>1</td> </tr> <tr style = " background: #eeeeee;"> <td>indexToLocFormat</td> <td>1</td> </tr> <tr> <td>glyphDataFormat</td> <td>0</td> </tr> </table> == '''関連記事''' == :[[フォント OpenType 構造解析]] : [[FreeTypeをコンパイル]] :[[FreeTypeを使う]] [[フォント]]に戻る。
フォント TrueType 構造解析
に戻る。
個人用ツール
ログイン
名前空間
ページ
議論
変種
表示
閲覧
ソースを表示
履歴表示
操作
検索
案内
メインページ
コミュニティ・ポータル
最近の出来事
最近の更新
おまかせ表示
ヘルプ
ツールボックス
リンク元
関連ページの更新状況
特別ページ