フォント TrueType 構造解析のソースを表示
新しいページはコチラ
移動:
案内
,
検索
[[フォント]]に戻る。 == 概要 == 仕様書はAppleのホームページに掲載されています。この記事で頑張って読みこみたいと思います。 [https://developer.apple.com/fonts/TrueType-Reference-Manual/ https://developer.apple.com/fonts/TrueType-Reference-Manual/] オープンタイプはこちら [https://docs.microsoft.com/en-us/typography/opentype/spec/ https://docs.microsoft.com/en-us/typography/opentype/spec/] OpenTypeとTrueTypeの違いってあるんですけど、ほとんどは同じです。何にも変わらないことだらけ。でも侮っていると、全然違う部分に迷い込んでたりする。注意は必要。ずっと解析してると。どっち見ても同じなので、普通にOpenTypeの仕様書を読みながらTrueTypeを解析してたりする。あぶねぇわな。 手動で読み解いてもすぐ忘れてしまうし、プログラムを使ってフォント構造をなんらかの方法で処理して理解を助けるようなものを作りたいと思います。できれば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テーブルは固定長(0x36 Byte)です。朱色のアンダーラインは、他のテーブルでも利用する値です。 <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>MajorVersion</td> <td>メジャーバージョン</td> </tr> <tr> <td>unsigned short</td> <td>MinorVersion</td> <td>マイナーバージョン</td> </tr> <tr style = " background: #eeeeee;"> <td>FixPoint16.16</td> <td>FixedfontRevision</td> <td>16.16固定小数点</td> </tr> <tr> <td>unsigned int</td> <td><span style = "background:linear-gradient(transparent 75%, #ff9393 75%); font-weight:bold; ">checkSumAdjustment</span></td> <td>前の項目で説明したとおり</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned int</td> <td>magicNumber</td> <td>0x5f0f3cf5で固定</td> </tr> <tr> <td>unsigned short</td> <td>flags</td> <td>※1</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>unitsPerEm</td> <td>1文字(EM)あたりのピクセル数</td> </tr> <tr> <td>unsigned long long</td> <td>CreateDate</td> <td>作成日</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned long long</td> <td>ModifyDate</td> <td>編集日</td> </tr> <tr> <td>unsigned short</td> <td>xMin</td> <td>水平方向有効最小座標値</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>yMin</td> <td>垂直方向有効最小座標値</td> </tr> <tr> <td>unsigned short</td> <td>xMax</td> <td>水平方向有効最大座標値</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>yMax</td> <td>垂直方向有効最大座標値</td> </tr> <tr> <td>unsigned short</td> <td>macStyle</td> <td>mac向けスタイルフラグ。OS/2 テーブルの fsSelection ビットと一致させる。※2</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>lowestRecPPEM</td> <td>文字が可読となる最小の1EMあたりのピクセル表現値</td> </tr> <tr> <td>short</td> <td>fontDirectionHint</td> <td>フォント記述方向 0:両方、1 : 左から右、2:左から右と移動無し、-1 : 右から左、-2:右から左と移動無し</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td><span style = "background:linear-gradient(transparent 75%, #ff9393 75%); font-weight:bold; ">indexToLocFormat</span></td> <td>タグ名loca1のテーブルにおけるOffset形式 0 : unsigned short16、 1 : unsigned int32</td> </tr> <tr> <td>unsigned short</td> <td>glyphDataFormat</td> <td>グリフ記述形式 現時点では0のみ</td> </tr> </table> ※1. flagは各ビット毎に以下のような意味になります。 bit 0:y=0がベースラインなら1 bit 1 : 左端の黒がLSB(Left Side Bearing) bit 2 : スケーリングされたポイントサイズと実際のポイントサイズで字形が異なる。 bit 3 : 分数スケールが含まれる場合に整数スケールを利用する。 bit 4 : マイクロソフトが提供するTrueTypeスケーラを利用する。 bit 5 : 垂直方向にレイアウトされ、x 座標 0 が目的の垂直ベースラインに対応するようにグリフが描画されたフォントに設定する必要がある。 bit 6 : このビットはゼロで固定。 bit 7 : フォントが正しい言語レンダリング(アラビア語フォントなど)の合字レイアウトを必要とする場合に設定する。 bit 8 : 規定値で発生していると指定されている1つ以上の特異効果 Apple Advanced Typographyを持つ場合に設定が必要。 bit 9 : フォントに右から左への強いグリフが含まれている場合に設定する必要がある。 bit 10 : フォントにインド風の並べ替え効果が含まれている場合に設定する必要がある。 bit11~13 : Adobeによって定義されている。 bit 14 : フォント内のグリフが、 last resort font(豆腐文字の先進的なモノ)など、コードポイント範囲の単なる汎用シンボルがある場合に、このビットを設定する必要がある。 ※2.macfontStyleは以下のようなフラグです。 bit 0 : 太字 bit 1 : 斜体 bit 2 : 下線 bit 3 : アウトライン bit 4 : シャドウ bit 5 : 凝縮 (狭) bit 6 : 拡張 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 ※0001_1011 bit4,3,1,0 </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> ==== maxp ==== maxpテーブルは固定長(0x20 Byte)です。主にグリフ全体における各要素の最大値を示しています。メモリをどれくらい確保していればグリフが確実に読み込めるかといった目安にもなります。基本的には動的にメモリを確保すると思いますが、メモリ不足を事前に察知することができます。総グリフ数は他のテーブルでも利用します。 <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>Value</th> </tr> <tr style = " background: #eeeeee;"> <td>Fixed 16.16</td> <td>Fixedversion</td> <td>0b0000000100000000 1.00=TrueTypeアウトラインフォント<br/>0b0000000101010000 0.3125=PostScriptアウトライン</td> </tr> <tr> <td>unsigned short</td> <td><span style = "background:linear-gradient(transparent 75%, #ff9393 75%); font-weight:bold; ">numGlyphs</span></td> <td>グリフ数</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>maxPoints</td> <td>単一グリフの最大ポイント数</td> </tr> <tr> <td>unsigned short</td> <td>maxContours</td> <td>単一グリフの最大輪郭(りんかく)数</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>maxCompositePoints</td> <td>複合グリフの最大ポイント数 複合グリフに使う単一グリフのポイント数の足し算なので、どのグリフが複合で使われるかによって決まるため、上記項目の単一グリフの最大値とはあまり関連はないものです。</td> </tr> <tr> <td>unsigned short</td> <td>maxCompsiteContours</td> <td>複合グリフの最大輪郭数。上記に同じく</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>maxZones</td> <td>1 : Z0命令を使う。2 : Z0命令を使わない。</td> </tr> <tr> <td>unsigned short</td> <td>maxTwilightPoints</td> <td>最大Z0命令使用数。</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>maxStorage</td> <td>ストレージエリア最大数</td> </tr> <tr> <td>unsigned short</td> <td>maxFunctionDefs</td> <td>最大FDEF数</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>maxInstructionDefs</td> <td>最大IDEF数</td> </tr> <tr> <td>unsigned short</td> <td>maxStackElements</td> <td>最大スタック深さ</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>maxSizeOfInstructions</td> <td>最大命令数</td> </tr> <tr> <td>unsigned short</td> <td>maxComponentElements</td> <td>最大複合グリフ要素利用数</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>maxComponentDepth</td> <td>最大複合グリフ再帰深度</td> </tr> </table> グリフ数は以下のテーブルに影響を与えます。 *グリフ位置テーブル ('loca') *グリフデータテーブル ('glyf') *'Zapf' テーブル さらに、一部のテーブルにはグリフインデックスが含まれており、フォントからグリフを削除した場合に更新が必要になる場合があります。このようなテーブルの部分的なリストは次のとおりです。 *文字グリフマッピングテーブル ('cmap') *妥当性テーブル ('just') *カーニングテーブル ('kern') *拡張グリフ変態テーブル ('morx') これらの整合性を保って、編集すれば、不要なグリフを削除するといったサブセット化はできそうですね。 でも、ここに来て、今まで知らなかった技術のいくつかを知る。それが、<span style = "background:linear-gradient(transparent 75%, #7fbfff 75%); font-weight:bold; ">フォントヒンティング</span>、<span style = "background:linear-gradient(transparent 75%, #7fbfff 75%); font-weight:bold; ">命令スタック</span>、<span style = "background:linear-gradient(transparent 75%, #7fbfff 75%); font-weight:bold; ">再帰</span>、<span style = "background:linear-gradient(transparent 75%, #7fbfff 75%); font-weight:bold; ">トワイライトポイント</span>、<span style = "background:linear-gradient(transparent 75%, #7fbfff 75%); font-weight:bold; ">ストレージ</span>といったあたり。 いやはや、これは深い。そりゃこんだけ沢山タグがあるわけだな。フォントは深い。知り尽くせぬほど深そうだ。もうちょっと仕様書とか文献を読み込みます。日本でフォントに詳しい文書書いてる人はGoogleでは10人くらいな感じがする。グラフ用紙に「ねこ」という2文字をプロットしてる深いサイトとopnetypeのタグの半分くらいにふれているサイト。凄すぎる。あっちこちいったりきたりして勉強だな。 フォントヒンティングはwikipediaによると文字が小さくなったときに頂点の位置を変更する場所みたいな説明だった。参考画像をみると確かにフォントヒンティングがあるほうが小さい文字を読み取りやすい。優れた技術だ。ちなみにfontforgeでさえもフォントヒンティングは読み込まないらしい。fontforgeでは編集できないそうな。コピーしたり自動生成?したりするらしい。説明によるとユーザインターフェースを提供しにくいそうだ。あれだけのものを作る人が諦めるってことは、ヒント関連ってむずかしそうだな。 この時代になってなお、無料ではまだ、フォントの奥深いところは素人には簡単に手出しできない状態になっているようだ。有料版とか企業がつかってるフォントエディタってすごいんかな。気になる。企業だけしか持ててないから、優秀なフォントは生まれにくいのかもしれない。個人でもきっかけさえあればすごいことやってのける時代だけど、環境がなければ、たやすくは生まれないんだな。 ともかく、 以下が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>Fixedversion</td> <td style = "text-align: right;">1.00</td> </tr> <tr> <td>numGlyphs</td> <td style = "text-align: right;">1019</td> </tr> <tr style = " background: #eeeeee;"> <td>maxPoints</td> <td style = "text-align: right;">242</td> </tr> <tr> <td>maxContours</td> <td style = "text-align: right;">60</td> </tr> <tr style = " background: #eeeeee;"> <td>maxCompositePoints</td> <td style = "text-align: right;">82</td> </tr> <tr> <td>maxCompsiteContours</td> <td style = "text-align: right;">5</td> </tr> <tr style = " background: #eeeeee;"> <td>maxZones</td> <td style = "text-align: right;">2</td> </tr> <tr> <td>maxTwilightPoints</td> <td style = "text-align: right;">16</td> </tr> <tr style = " background: #eeeeee;"> <td>maxStorage</td> <td style = "text-align: right;">47</td> </tr> <tr> <td>maxFunctionDefs</td> <td style = "text-align: right;">86</td> </tr> <tr style = " background: #eeeeee;"> <td>maxInstructionDefs</td> <td style = "text-align: right;">0</td> </tr> <tr> <td>maxStackElements</td> <td style = "text-align: right;">913</td> </tr> <tr style = " background: #eeeeee;"> <td>maxSizeOfInstructions</td> <td style = "text-align: right;">408</td> </tr> <tr> <td>maxComponentElements</td> <td style = "text-align: right;">3</td> </tr> <tr style = " background: #eeeeee;"> <td>maxComponentDepth</td> <td style = "text-align: right;">1</td> </tr> </table> 英語フォントの癖にスタックが913とかマジか。トワイライトポイントが16ってことはあんまり沢山せっていするものではないんだな。なんだろこれ。あとストレージエリアの47は多い奴は結構あるんだなっていう印象。なんかわかったら、追記します。追記がないあいだは、こいつ、いろいろ書いてるくせに理解できていないと思って下さい。 ==== hhea、hmtx ==== hheaテーブルは固定長(0x24 Byte)です。水平レイアウト情報です。hmtxテーブルはグリフ数で決まる可変長です。各グリフの横送り幅と送り幅の左側を起点として、文字の黒色がある一番左の位置の情報をもっています。LSBと呼びます。Left Side Bearingです。このときのBearingは位置認識という意味を持ちます。挙動という意味もありますが、こちらが、軸受けなんかに使われるボールベアリングの意味だと思われです。 水平方向にフォントを並べていくとき使われる情報です。'''h'''orizontal '''hea'''dで、hheaだと思われます。 各グリフの情報をもつという意味で'''h'''orizontal '''m'''a'''t'''ri'''x'''で、hmtxだと思われます。確度が高いとは思いますが、推測情報ばかりで申し訳ないです。 <big>'''■hhea'''</big> <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>MajorVersion</td> <td>メジャーバージョン</td> </tr> <tr> <td>unsigned short</td> <td>MinorVersion</td> <td>マイナーバージョン</td> </tr> <tr style = " background: #eeeeee;"> <td>short</td> <td>Ascent</td> <td>高さ</td> </tr> <tr> <td>unsigned short</td> <td>Descender</td> <td>ベースラインの下</td> </tr> <tr style = " background: #eeeeee;"> <td>short</td> <td>LineGap</td> <td>行間</td> </tr> <tr> <td>unsigned short</td> <td>AdvanceWidthMax</td> <td>最大文字の送り幅</td> </tr> <tr style = " background: #eeeeee;"> <td>short</td> <td>MinLeftSideBearing</td> <td>送り幅枠左基準の最小の左側黒色部の座標</td> </tr> <tr> <td>short</td> <td>MinRightSideBearing</td> <td>送り幅枠右基準の最小の右側黒色部の座標</td> </tr> <tr style = " background: #eeeeee;"> <td>short</td> <td>XMaxExtent</td> <td>左下原点から右黒色部の最大値</td> </tr> <tr> <td>short</td> <td>CaretSlopeRise</td> <td>斜体角度垂直ならtan90度でCaretSlopeRise:1/CaretSlopeRun:0。</td> </tr> <tr style = " background: #eeeeee;"> <td>short</td> <td>CaretSlopeRun</td> <td>上記説明のとおり</td> </tr> <tr> <td>short</td> <td>CaretOffset</td> <td>斜体分のカーソル移動量</td> </tr> <tr style = " background: #eeeeee;"> <td>short</td> <td>MetricDataFormat</td> <td>hmtx テーブルのデータフォーマット。現時点で0のみ</td> </tr> <tr> <td>unsigned short</td> <td><span style = "background:linear-gradient(transparent 75%, #ff9393 75%); font-weight:bold; ">NumberOfMetrics</span></td> <td>各グリフのAdvanceWidth、LSB定義数</td> </tr> </table> 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 style = "text-align: right;">1</td> </tr> <tr> <td>MinorVersion</td> <td style = "text-align: right;">0</td> </tr> <tr style = " background: #eeeeee;"> <td>Ascent</td> <td style = "text-align: right;">2066</td> </tr> <tr> <td>numGlyphs</td> <td style = "text-align: right;">-432</td> </tr> <tr style = " background: #eeeeee;"> <td>LineGap</td> <td style = "text-align: right;">0</td> </tr> <tr> <td>AdvanceWidthMax</td> <td style = "text-align: right;">2974</td> </tr> <tr style = " background: #eeeeee;"> <td>MinLeftSideBearing</td> <td style = "text-align: right;">-265</td> </tr> <tr> <td>MinRightSideBearing</td> <td style = "text-align: right;">-265</td> </tr> <tr style = " background: #eeeeee;"> <td>XMaxExtent</td> <td style = "text-align: right;">2894</td> </tr> <tr> <td>CaretSlopeRise</td> <td style = "text-align: right;">1</td> </tr> <tr style = " background: #eeeeee;"> <td>CaretSlopeRun</td> <td style = "text-align: right;">0</td> </tr> <tr> <td>CaretOffset</td> <td style = "text-align: right;">0</td> </tr> <tr style = " background: #eeeeee;"> <td>MetricDataFormat</td> <td style = "text-align: right;">0</td> </tr> <tr> <td>NumberOfMetrics</td> <td style = "text-align: right;">1019</td> </tr> </table> hmtx の IMPACTの結果は以下の通りです。各グリフ毎にある値なので1019行を超えるため、テキストへのリンクを貼り付けておきます。これだけの値を手作業でまとめることは無謀すぎます。ようやっとでプログラムで動かしてるんだなって思ってもらえると思います。 [[メディア:IMPACT TAG hmtx TebleInfo.txt|IMPACT_TAG_hmtx_TebleInfo.txt]] つかっているプログラムは、もし完成することがあるならば有用なものになるかもしれないので、Qtのライセンスに触れない形式でアップロードするかもしれません。商用の扱いはダメですからね。 <big>'''■hmtx'''</big> <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr style = " background: #eeeeee;"> <td>longHorMetric</td> <td>hMetrics[GlyphID]</td> <td>グリフID毎のAdvaceWidthとLSB longHorMetric構造体は後述</td> </tr> <tr> <td>short</td> <td>leftSideBearing[GlyphID]</td> <td>hMetricsで記述されなかった残りのグリフID毎のLSB</td> </tr> </table> '''※longHorMetric構造体''' <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>advaceWidth</td> <td>グリフの送り幅</td> </tr> <tr> <td>short</td> <td>leftSideBearing</td> <td>グリフのLSB</td> </tr> </table> hmtxでは、グリフの送り幅とLSBを構造体の形式とみなしてGlyphID順に読み込んでいきます。hheaのNumberOfMetricsで定義された分だけ構造体が配列のように読み取ることができるようになっています。maxpで定義されたNumGlyphsの値よりNumberOfMetricsが少ない場合は、残りのadvanceWidthは配列の最後の値がすべてに適用されます。残りのLSBは別途、グリフ毎に定義することが必要になっています。 ==== OS/2 ==== OS/2テーブルはフォントのコンピュータが取り扱うために必要な基本的な数値情報が格納されています。OS/2はIBMやMicrosoftのオペレーティングシステムの名前でどちらもOS/2の愛称がありました。一番流行っていたオペレーティングシステムとやりとりする主な値なのでこのような後世に残るようなテーブル名をつけてしまったのだと思います。OS/2自体は、みかけなくなりましたが、このワードは今も生きています。OS/2テーブルのバージョン毎に長さが変わります。Version0なら0x4cByte Version1では、0x54Byte。Version2、3および4だと0x60Byteです。Version5なら0x68Byteになります。 <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>unsigned short</td> <td>UsVersion</td> <td>テーブルバージョン番号 0~5</td> </tr> <tr style = " background: #eeeeee;"> <td>short</td> <td>SXAvgCharWidth</td> <td>フォント平均文字幅</td> </tr> <tr> <td>unsigned short</td> <td>UsWeightClass</td> <td>フォント太さ指標 ※1</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>UsWidthClass</td> <td>フォント文字幅指標 ※2</td> </tr> <tr> <td>unsigned short</td> <td>usType</td> <td>フォント取り扱い各種フラグ ※3</td> </tr> <tr style = " background: #eeeeee;"> <td>short</td> <td>SSubscriptXSize</td> <td>下付き文字の横幅</td> </tr> <tr> <td>short</td> <td>SSubscriptYSize</td> <td>下付き文字の高さ</td> </tr> <tr style = " background: #eeeeee;"> <td>short</td> <td>SSubscriptXOffset</td> <td>下付き文字の横位置</td> </tr> <tr> <td>short</td> <td>SSubscriptYOffset</td> <td>下付き文字の縦位置</td> </tr> <tr style = " background: #eeeeee;"> <td>short</td> <td>SSuperscriptXSize</td> <td>上付き文字の横幅</td> </tr> <tr> <td>short</td> <td>SSuperscriptYSize</td> <td>上付き文字の縦幅</td> </tr> <tr style = " background: #eeeeee;"> <td>short</td> <td>SSuperscriptXOffset</td> <td>上付き文字の横位置</td> </tr> <tr> <td>short</td> <td>SSuperscriptYOffset</td> <td>上付き文字の縦位置</td> </tr> <tr style = " background: #eeeeee;"> <td>short</td> <td>SStrikeoutSize</td> <td>取り消し線の太さ</td> </tr> <tr> <td>short</td> <td>SStrikeoutPosition</td> <td>取り消し線のベースラインからの縦位置</td> </tr> <tr style = " background: #eeeeee;"> <td>short</td> <td>SFamilyClass</td> <td>上位バイト=ファミリークラス、下位バイト=サブクラス ※4</td> </tr> <tr> <td>unsigned char</td> <td>ucPanose[0]</td> <td>書体特性 ※5</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned char</td> <td>ucPanose[1]</td> <td></td> </tr> <tr> <td>unsigned char</td> <td>ucPanose[2]</td> <td></td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned char</td> <td>ucPanose[3]</td> <td></td> </tr> <tr> <td>unsigned char</td> <td>ucPanose[4]</td> <td></td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned char</td> <td>ucPanose[5]</td> <td></td> </tr> <tr> <td>unsigned char</td> <td>ucPanose[6]</td> <td></td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned char</td> <td>ucPanose[7]</td> <td></td> </tr> <tr> <td>unsigned char</td> <td>ucPanose[8]</td> <td></td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned char</td> <td>ucPanose[9]</td> <td></td> </tr> <tr> <td>unsigned int</td> <td>UiUnicodeRange1</td> <td>1~4まで128バイトのフラグ ※6</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned int</td> <td>UiUnicodeRange2</td> <td></td> </tr> <tr> <td>unsigned int</td> <td>UiUnicodeRange3</td> <td></td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned int</td> <td>UiUnicodeRange4</td> <td></td> </tr> <tr> <td>unsigned char[4]</td> <td>ucAchVendID</td> <td>ASCIIコード4文字のフォントベンダーID</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>FsSelection</td> <td>フォントパターンフラグ ※7</td> </tr> <tr> <td>unsigned short</td> <td>UsFirstCharIndex</td> <td>最小ユニコード番号32</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>UsLastCharIndex</td> <td>最大ユニコード番号32</td> </tr> <tr> <td>unsigned short</td> <td>STypoAscender</td> <td>印刷するときのグリフ高さ</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>STypoDescender</td> <td>-印刷するときのグリフ深さ</td> </tr> <tr> <td>unsigned short</td> <td>STypoLineGap</td> <td>印刷するときの行間</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>UsWinAscent</td> <td>Windowsでのグリフ高さ</td> </tr> <tr> <td>unsigned short</td> <td>UsWinDescent</td> <td>Windowsでのグリフ深さ</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned int</td> <td>UiCodePageRange1</td> <td>1~2の64bitの含まれるコードページ言語のフラグ</td> </tr> <tr> <td>unsigned int</td> <td>UiCodePageRange2</td> <td>UiUnicodeRangeと同じような仕組みです。</td> </tr> <tr style = " background: #eeeeee;"> <td>short</td> <td>SXHeight</td> <td>ベースラインと小文字xの高さ</td> </tr> <tr> <td>short</td> <td>SCapHeight</td> <td>ベースラインと大文字Hの高さ</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>UsDefaultChar</td> <td>フォントが無い場合に参照されるグリフ番号 0 になることが多い。</td> </tr> <tr> <td>unsigned short</td> <td>UsBreakChar</td> <td>ブレーク文字の規定値 ほとんどが0x20半角空白スペース</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>UsMaxContext</td> <td>合字で扱う最大グリフ数</td> </tr> <tr> <td>unsigned short</td> <td>UsLowerOpticalPointSize</td> <td>フォントが使われる最小サイズ</td> </tr> <tr style = " background: #eeeeee;"> <td>unsigned short</td> <td>UsUpperOpticalPointSize</td> <td>フォントが使われる最大サイズ</td> </tr> </table> *xAvgCharWidth : 小文字26文字すべてがないと0になります。小文字のみの、advanceWidth送り幅の平均ですが、単純な値ではないです。使用頻度に応じた重みづけ係数表を使った計算をします。(a送り幅x係数+…z送り幅 + 空白送り幅x係数)/1000の値です。この値は文字数 x 送り幅で1行の文字長さを推測できるもだそうです。 <table border=1> <tr> <th style = " background: #778ca3;">字</th><th>係数</th><th style = " background: #778ca3;">字</th><th>係数</th><th style = " background: #778ca3;">字</th><th>係数</th><th style = " background: #778ca3;">字</th><th>係数</th><th style = " background: #778ca3;">字</th><th>係数</th> </tr> <tr> <td style = " background: #778ca3;">a</td><td>64</td><td style = " background: #778ca3;">b</td><td>14</td><td style = " background: #778ca3;">c</td><td>27</td><td style = " background: #778ca3;">d</td><td>35</td><td style = " background: #778ca3;">e</td><td>100</td> </tr> <tr> <td style = " background: #778ca3;">f</td><td>20</td><td style = " background: #778ca3;">g</td><td>14</td><td style = " background: #778ca3;">h</td><td>42</td><td style = " background: #778ca3;">i</td><td>63</td><td style = " background: #778ca3;">j</td><td>3</td> </tr> <tr> <td style = " background: #778ca3;">k</td><td>6</td><td style = " background: #778ca3;">l</td><td>35</td><td style = " background: #778ca3;">m</td><td>20</td><td style = " background: #778ca3;">n</td><td>56</td><td style = " background: #778ca3;">o</td><td>56</td> </tr> <tr> <td style = " background: #778ca3;">p</td><td>17</td><td style = " background: #778ca3;">q</td><td>4</td><td style = " background: #778ca3;">r</td><td>49</td><td style = " background: #778ca3;">s</td><td>56</td><td style = " background: #778ca3;">t</td><td>71</td> </tr> <tr> <td style = " background: #778ca3;">u</td><td>31</td><td style = " background: #778ca3;">v</td><td>10</td><td style = " background: #778ca3;">w</td><td>18</td><td style = " background: #778ca3;">x</td><td>3</td><td style = " background: #778ca3;">y</td><td>18</td> </tr> <tr> <td style = " background: #778ca3;">z</td><td>2</td><td style = " background: #778ca3;">sp</td><td>166</td><td></td><td></td><td></td><td></td><td></td><td></td> </tr> </table> ※1usWeightClassは100~900の100の倍数で指定される指標です。 100 Ultra-light 200 Extra-light 300 Light 400 Semi-light 500 Medium 600 Semi-Bold 700 Bold 800 Extra-Bold 900 Ultra-Bold ※2usWidthClassは文字幅の指標です。 1 Ultra-condensed 50% 2 Extra-condensed 63.5% 3 condensed 75% 4 semi-condensed 87.5% 5 Medium 100% 6 Semi-Expanded 112.5% 7 Expanded 125% 8 Extra-expanded 150% 9 Ultra-expanded 200% ※3 フォント取り扱いフラグ Bit 0 : 予約 = 0 Bit 1 : Bit2あるいは3が1のときは1であってはならないフラグです。所有者に許可なく埋め込み、編集、ファイル交換してはならないです。 Bit 2 : Bit1あるいは3が1のときは1であってはならないフラグです。そのまま埋め込みしてもよいですが、リモートでフォントが表示されるドキュメントは読み取り専用になっていないといけない。 Bit 3 : フォントファイルを編集しての埋め込みが許されています。 Bit 4-7 : 予約 = 0 Bit 8 : サブセット化しようとする文書の出力の仕組みを許可しないです。 Bit 9 :ビットマップによる埋め込みのみ許可 Bit 10-15 : 予約 = 0 ※4 SFamilyClass 文字のデザイン分類をするものです。作ってる人も分類むずかしいでしょうね。 ファミリークラス分類 Bit 0 : 分類なし Bit 1 : オールドスタイルセリフ 15世紀から17世紀のセリフスタイルです。 Bit 2 : 過度なセリフ 18世紀から19世紀のセリフスタイルです。 Bit 3 : モダンセリフ 20世紀。 Bit 4 : クラレンドンセリフ Bit 5 : スラブセリフ Bit 6 : 予約済 = 0 Bit 7 : フリーフォームセリフ。セリフはあるけど自由なものです。 Bit 8 : サンセリフ。セリフがないゴシック体のような文字 Bit 9 : 装飾。豪華な装飾がほどこされた字体です。 Bit 10 : スクリプト。手書きをシミュレートするような設計がされています。 Bit 11 : 予約済 = 0 Bit 12 : シンボリック。記号とか Bit 13-14 : 予約済 = 0 オールドスタイルセリフのサブクラスといったように上位バイトで決まる下位バイトの意味付け分類が存在します。1、2、3、4、5、7、8、9、10、12の10種類ある。 以下はオールドスタイルの例です。全部の分類を記述するのは大変なので、リンクを貼っておきます。 Bit 0 : 分類無し Bit 1 : 丸みを帯びている Bit 2 : ガラルデ Bit 3 : ベネチアン Bit 4 : モディファイベネチアン Bit 5 : 現代オランダ Bit 6 : 伝統オランダ Bit 7 : コンテンポラリ Bit 8 : カリグラフィ Bit 9-14 : 予約済 = 0 Bit 15 : 種々雑多な といったように上位バイトに基づいた分類がある。 ※5 PANOSE 1バイトの数値で以下0~9の10種類の様々なフラグがあります。 PANOSE[0] : bFamilyType : :0 : Any :1 : No Fit :2 : Text and Display :3 : Script :4 : Decorative :5 : Pictorial PANOSE[1] : bSerifStyle : :0 : Any :1 : No Fit :2 : Cove :3 : Obtuse Cove :4 : Square Cove :5 : Obutuse Square Cove :6 : Square :7 : Thin :8 : Bone :9 : Exaggerated :10 : Triangle :11 : Normal Sans :12 : Obtuse Sans :13 : Perp Sans :14 : Fiared :15 : Rounded PANOSE[2] : bWeight : :0 : Any :1 : No Fit :2 : Very Light :3 : Light :4 : Thin :5 : Book :6 : Medium :7 : Demi :8 : Bold :9 : Heavy :10 : Black :11 : Nord PANOSE[3] : bProportion : :0 : Any :1 : No Fit :2 : Old Style :3 : Modern :4 : Even Width :5 : Expanded :6 : Condensed :7 : Very Expanded :8 : Very Condensed :9 : MonoSpace PANOSE[4] : bContrast : :0 : Any :1 : No Fit :2 : None :3 : Very Low :4 : Low :5 : Medium Low :6 : Medium :7 : Medium High :8 : High :9 : Very High PANOSE[5] : bStrokeVariation : :0 : Any :1 : No Fit :2 : Gradual/Diagonal :3 : Gradual/Transitional :4 : Gradual/Vertical :5 : Gradual/Horizontal :6 : Rapid/Vertical :7 : Rapid/Horizontal :8 : Instant/Vertical PANOSE[6] : bArmStyle : :0 : Any :1 : No Fit :2 : Straight Arm/Horizontal :3 : Straight Arm/Wedge :4 : Straight Arm/Vertical :5 : Straight Arm/Single Serif :6 : Straight Arm/Double Serif :7 : Non-Straight Arm/Horizontal :8 : Non-Straight Arm/Wedge :9 : Non-Straight Arm/Vertical :10 : Non-Straight Arm/Single Serif :11 : Non-Straight Arm/Double Serif PANOSE[7] : bLetterform : :0 : Any :1 : No Fit :2 : Normal/Contact :3 : Normal/Weighted :4 : Normal/Boxed :5 : Normal/Flattened :6 : Normal/Rounded :7 : Normal/Off Centter :8 : Normal/Square :9 : Obliqui/Contact :10 : Obliqui/Weighted :11 : Obliqui/Boxed :12 : Obliqui/Flattened :13 : Obliqui/Rounded :14 : Obliqui/Off Centter :15 : Obliqui/Square PANOSE[8] : bSerifStyle : :0 : Any :1 : No Fit :2 : Standard/Trimmed :3 : Standard/Pointed :4 : Standard/Serifed :5 : High/Trimmed :6 : High/Pointed :7 : High/Serifed :8 : Constant/Trimmed :9 : Constant/Pointed :10 : Constant/Serifed :11 : Low/Trimmed :12 : Low/Pointer :13 : Low/Serifed PANOSE[9] : bXHeight : :0 : Any :1 : No Fit :2 : Constant/Small :3 : Constant/Standard :4 : Constant/Large :5 : Ducking/Small :6 : Ducking/Standart :7 : Ducking/Large ※6 uiUnicodeRange ユニコード使用範囲を指定する部分です。0~127のそれぞれのbitフラグがUnicodeの一定の範囲を指し示します。範囲についてはMicrosoftのOpentype仕様書に記述があります。 achVendID[4] 4文字のベンダーIDをMicrosoftが管理しています。 <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; ">VenderID</th> <th>名前</th> </tr> <tr style = " background: #eeeeee;"> <td>ACG </td> <td style = "text-align: right;">AGFA コンピュグラフィック</td> </tr>Adbe <tr> <td>Adbe</td> <td style = "text-align: right;">Adobe Systems</td> </tr> <tr style = " background: #eeeeee;"> <td>Appl</td> <td style = "text-align: right;">Apple</td> </tr>Adbe <tr> <td>Alts</td> <td style = "text-align: right;">AltSys</td> </tr> <tr style = " background: #eeeeee;"> <td>B? </td> <td style = "text-align: right;">Bigelow&Holmemes</td> </tr> <tr> <td>Bert</td> <td style = "text-align: right;">Berthold</td> </tr> <tr style = " background: #eeeeee;"> <td>Bits</td> <td style = "text-align: right;">BitStream</td> </tr> <tr> <td>DTC </td> <td style = "text-align: right;">ディジタルタイプフェイス Corp.</td> </tr> <tr style = " background: #eeeeee;"> <td>HP </td> <td style = "text-align: right;">ヒューレットパッカード</td> </tr> <tr> <td>IBM </td> <td style = "text-align: right;">IBM</td> </tr> <tr style = " background: #eeeeee;"> <td>KATF</td> <td style = "text-align: right;">Kingsley/ATF</td> </tr> <tr> <td>Lans</td> <td style = "text-align: right;">有限会社 Lanston タイプ</td> </tr> <tr style = " background: #eeeeee;"> <td>LETR</td> <td style = "text-align: right;">Letraset</td> </tr> <tr> <td>Lino</td> <td style = "text-align: right;">Linotype</td> </tr> <tr style = " background: #eeeeee;"> <td>MONO</td> <td style = "text-align: right;">モノタイプ</td> </tr> <tr> <td>MS </td> <td style = "text-align: right;">マイクロソフト</td> </tr> <tr style = " background: #eeeeee;"> <td>QMSI</td> <td style = "text-align: right;">QMS/Imagen</td> </tr> <tr> <td>URW</td> <td style = "text-align: right;">URW</td> </tr> <tr style = " background: #eeeeee;"> <td>ZSFT</td> <td style = "text-align: right;">ZSoft</td> </tr> </table> ※7 fsSelection フォントスタイルを選択するフラグ部分です。 Bit 0 : ITALIC 斜体 Bit 1 : UNDERSCORE 下線 Bit 2 : NEGATIVE 反転 Bit 3 : OUTLINED 輪郭 Bit 4 : STRIKEOUT 打消し線 Bit 5 : BOLD 太字 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>UsVersion</td> <td style = "text-align: right;">3</td> </tr> <tr> <td>SXAvgCharWidth</td> <td style = "text-align: right;">1222</td> </tr> <tr style = " background: #eeeeee;"> <td>UsWeightClass</td> <td style = "text-align: right;">400</td> </tr> <tr> <td>UsWidthClass</td> <td style = "text-align: right;">3</td> </tr> <tr style = " background: #eeeeee;"> <td>sFsType</td> <td style = "text-align: right;">8</td> </tr> <tr> <td>SSubscriptXSize</td> <td style = "text-align: right;">1184</td> </tr> <tr style = " background: #eeeeee;"> <td>SSubscriptYSize</td> <td style = "text-align: right;">1081</td> </tr> <tr> <td>SSubscriptXOffset</td> <td style = "text-align: right;">0</td> </tr> <tr style = " background: #eeeeee;"> <td>SSubscriptYOffset</td> <td style = "text-align: right;">0</td> </tr> <tr> <td>SSuperscriptXSize</td> <td style = "text-align: right;">1184</td> </tr> <tr style = " background: #eeeeee;"> <td>SSuperscriptYSize</td> <td style = "text-align: right;">1081</td> </tr> <tr> <td>SSuperscriptXOffset</td> <td style = "text-align: right;">0</td> </tr> <tr style = " background: #eeeeee;"> <td>SSuperscriptYOffset</td> <td style = "text-align: right;">800</td> </tr> <tr> <td>SStrikeoutSize</td> <td style = "text-align: right;">102</td> </tr> <tr style = " background: #eeeeee;"> <td>SStrikeoutPosition</td> <td style = "text-align: right;">690</td> </tr> <tr> <td>SFamilyClass</td> <td style = "text-align: right;">2053</td> </tr> <tr style = " background: #eeeeee;"> <td>ucPanose[0]</td> <td style = "text-align: right;">2</td> </tr> <tr> <td>ucPanose[1]</td> <td style = "text-align: right;">11</td> </tr> <tr style = " background: #eeeeee;"> <td>ucPanose[2]</td> <td style = "text-align: right;">8</td> </tr> <tr> <td>ucPanose[3]</td> <td style = "text-align: right;">6</td> </tr> <tr style = " background: #eeeeee;"> <td>ucPanose[4]</td> <td style = "text-align: right;">3</td> </tr> <tr> <td>ucPanose[5]</td> <td style = "text-align: right;">9</td> </tr> <tr style = " background: #eeeeee;"> <td>ucPanose[6]</td> <td style = "text-align: right;">2</td> </tr> <tr> <td>ucPanose[7]</td> <td style = "text-align: right;">5</td> </tr> <tr style = " background: #eeeeee;"> <td>ucPanose[8]</td> <td style = "text-align: right;">2</td> </tr> <tr> <td>ucPanose[9]</td> <td style = "text-align: right;">4</td> </tr> <tr style = " background: #eeeeee;"> <td>UiUnicodeRange1</td> <td style = "text-align: right;">0x00000287</td> </tr> <tr> <td>UiUnicodeRange2</td> <td style = "text-align: right;">0x00000000</td> </tr> <tr style = " background: #eeeeee;"> <td>UiUnicodeRange3</td> <td style = "text-align: right;">0x00000000</td> </tr> <tr> <td>UiUnicodeRange4</td> <td style = "text-align: right;">0x00000000</td> </tr> <tr style = " background: #eeeeee;"> <td>ucAchVendID</td> <td style = "text-align: right;">MONO</td> </tr> <tr> <td>FsSelection</td> <td style = "text-align: right;">64</td> </tr> <tr style = " background: #eeeeee;"> <td>UsFirstCharIndex</td> <td style = "text-align: right;">32</td> </tr> <tr> <td>UsLastCharIndex</td> <td style = "text-align: right;">64260</td> </tr> <tr style = " background: #eeeeee;"> <td>STypoAscender</td> <td style = "text-align: right;">1619</td> </tr> <tr> <td>STypoDescender</td> <td style = "text-align: right;">-229</td> </tr> <tr style = " background: #eeeeee;"> <td>STypoLineGap</td> <td style = "text-align: right;">343</td> </tr> <tr> <td>UsWinAscent</td> <td style = "text-align: right;">2066</td> </tr> <tr style = " background: #eeeeee;"> <td>UsWinDescent</td> <td style = "text-align: right;">432</td> </tr> <tr> <td>UiCodePageRange1</td> <td style = "text-align: right;">0x2000009f</td> </tr> <tr style = " background: #eeeeee;"> <td>UiCodePageRange2</td> <td style = "text-align: right;">0xdfd70000</td> </tr> <tr> <td>SXHeight</td> <td style = "text-align: right;">1327</td> </tr> <tr style = " background: #eeeeee;"> <td>SCapHeight</td> <td style = "text-align: right;">1619</td> </tr> <tr> <td>UsDefaultChar</td> <td style = "text-align: right;">0</td> </tr> <tr style = " background: #eeeeee;"> <td>UsBreakChar</td> <td style = "text-align: right;">32</td> </tr> <tr> <td>UsMaxContext</td> <td style = "text-align: right;">5</td> </tr> <tr style = " background: #eeeeee;"> <td>UsLowerOpticalPointSize</td> <td style = "text-align: right;">0</td> </tr> <tr> <td>UsUpperOpticalPointSize</td> <td style = "text-align: right;">64565</td> </tr> </table> ==== LTSH スケール系==== グリフの数だけ unsigned char 型の配列をもつ可変長のテーブルです。サイドベアリングが無い場合は常に線形であることを意味する1とする必要がある値で、LinearThreSHoldの意です。headテーブルのflag値のbit4:マイクロソフトのスケーラを使うを有効にしたときにだけLTSH指定するのが一般的な使い方です。0~255の値でグリフを線形にスケーリングできる垂直骨の高さを1emあたりの数値として指定します。0~255ピクセルの大きさにスケールしたときに線形しはじめるのはどこからかというテーブルだと思います。小さい文字にはヒントにしたがったリニアスケールではない値という意味です。1だと、とにかくリニアスケール(単純な拡大・縮小)っていう感じなのかな。もうちょっと確信をもてるような文献にであえたら続報あるかもしれません。 <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>unsigned short</td> <td>UsVersion</td> <td>テーブルバージョン番号 0</td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned short</td> <td><span style = "background:linear-gradient(transparent 75%, #ff9393 75%); font-weight:bold; ">UsNumGlyphs</span></td> <td>グリフ数</td> </tr> <tr> <td>unsigned char</td> <td>UcPels[NumGlyphs]</td> <td>各グリフのスケール垂直骨高さ</td> </tr> </table> IMPACT.ttfの設定内容は以下の通りでした。グリフの数だけある線形スケーリング垂直骨高さなので、テキストファイルのリンクを示します。 [[メディア:IMPACT TAG LTSH TebleInfo.txt|IMPACT_TAG_LTSH_TebleInfo.txt]] ==== VDMX スケール系 ==== VDMXはVertical Device Metric の意味でOS/2テーブルのusWinAscentとusWinDescentの値から任意のサイズのフォントにおける最大の黒色部分高さを決定します。スケーリングによる高さと丸め込み量による高さとで異なるフォント高さになるため、yMaxやyMinから飛び出ることがないように定義されます。VDMXヘッダーにアスペクト比ごとにグループ化したときの総数だけratRange構造体を保有する可変量と総数だけテーブル開始位置からの記載ポジションを設定する可変量を保有しています。ratRange構造体が4バイトです。そしてVDMXレコードが続きます。高さレコードの数だけ1レコード12byteのvTable構造体を持ちます。VDMXタグテーブルは大きな配列になります。アスペクト比ごとのグループ?なんそれって感じでマイクロソフトの仕様書のページにいくと分類が乗ってました。なるほどxとyの比率を検出して、どのテーブルを使うべきかを検出するそうな。それで、ratRagneのxRatio、yStartRatio、yEndRatioが0,0,0になっているのが全ての比率に対応するグループのテーブルなのでこれが見つかると検索を終了するので、0,0,0は配列の最後に配置するべきだそうです。いやー、これは深い。ratRagneのbCharSetの意味はテーブルバージョンによって変わることになっています。Version 0 の bCharset 1のみすべてのグリフに適用せずANSIコードのみに適用されることになります。Version 1の利用が推奨されているようです。bCharset 0 は既存のフォントに追加する場合、1 は全く新しいフォント用に使うことになっています。 ■VDMX Header <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>unsigned short</td> <td>UsVersion</td> <td>テーブルバージョン番号 0 or 1</td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned short</td> <td>UsNumRecs</td> <td>VDMXグループ数</td> </tr> <tr> <td>unsigned short</td> <td>UsNumRatios</td> <td>アスペクト比ごとのグループ数</td> </tr> <tr style = " background: #eeeeee;" > <td>ratioRange構造体</td> <td>ratRange[UsNumRatios]</td> <td>numRatioの数の配列のratRage構造体</td> </tr> <tr> <td>unsigned int</td> <td>vdmxGroupOffsets[UsNumRatios]</td> <td>numRatioの数の配列のテーブル先頭からのアドレス位置</td> </tr> </table> ■ratRagne構造体 <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>unsigned char</td> <td>bCharSet</td> <td>文字セット</td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned char</td> <td>xRatio</td> <td>x-Ratioのために使う値</td> </tr> <tr> <td>unsigned char</td> <td>yStartRatio</td> <td>y-Ratioの開始値</td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned char</td> <td>yEndRatio</td> <td>y-Ratioの終了値</td> </tr> </table> ■VDMX Record <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>unsigned short</td> <td>UsRecs</td> <td>高さレコード数</td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned char</td> <td>ucStartsz</td> <td>y垂直骨高さ開始値</td> </tr> <tr> <td>unsigned char</td> <td>ucEndsz</td> <td>y垂直骨高さ終了値</td> </tr> <tr style = " background: #eeeeee;" > <td>vTable構造体</td> <td>vTable_Entry[usRecs]</td> <td>numRatioの数の配列のratRage構造体</td> </tr> </table> ■vTable構造体 <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>unsigned short</td> <td>yPelHeight</td> <td>適用するyPel値</td> </tr> <tr style = " background: #eeeeee;" > <td>short</td> <td>yMax</td> <td>yPelのための最大値</td> </tr> <tr> <td>short</td> <td>yMin</td> <td>yPelのための最小値</td> </tr> </table> IMPACT.ttfの場合は以下のようになっていました。ものすごい細かく設定されてるんですね。フォントファイル制作ってやっぱスゴイな。 [[メディア:IMPACT TAG VDMX TebleInfo.txt|IMPACT_TAG_VDMX_TebleInfo.txt]] ==== hdmx スケール系 ==== hdmxはHorizontal Device Metricの意味でVDMXは大文字でしたが、水平方向についての定義です。このテーブルもheadテーブルのflag値のbit 4 が 1 である場合にのみ使われることが推奨されています。 <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>unsigned short</td> <td>UsVersion</td> <td>テーブルバージョン番号 0 </td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned short</td> <td>usNumRecord</td> <td>レコード数</td> </tr> <tr> <td>unsigned int</td> <td>UiSizeDeviceRecord</td> <td>DeviceRecordテーブルの大きさ。NumGlyph+2より大きい値</td> </tr> <tr style = " background: #eeeeee;" > <td>DeviceRecords</td> <td>Record[NumRecord]</td> <td>DeviceRecords構造体</td> </tr> </table> ■DeviceRecord構造体 <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>unsigned char</td> <td>ucPixelSize</td> <td>ピクセルサイズ </td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned char</td> <td>ucMaxWidth</td> <td>最大幅</td> </tr> <tr> <td>unsigned char</td> <td>ucWidths[numGlyph]</td> <td>各グリフごとの送り幅</td> </tr> </table> 全部がツメツメに格納されているわけではなく、1つのRecord番号のDeviceRecord構造体を記述するときにUiSizeDeviceRecordの長さになっていることは注意するべきところで、2+numGlyph数からUiSizeDeviceRecord Byteの分までを0x00でPaddingをしないといけません。 IMPACT.ttfの内容は以下のファイルリンクの通りになります。割かし長いテーブル内容です。 [[メディア:IMPACT TAG hdmx TebleInfo.txt|IMPACT_TAG_hdmx_TebleInfo.txt]] ==== cmap ==== 文字コードをうけとって、グリフIDに変換して、必要なグリフ表示を行うための対応表です。最近はUnicodeを受け取る方式のフォントファイルcmapが準備されていることが多いそうです。他の方法もあるのは手ごわい。あんまり使われない方法も知らないといけないんだなぁ。やだな。 中規模の可変長のテーブルになることが多いです。ややこしさはglypの実体テーブルの次くらいだという感じです。理解できるかどうかわかりませんが、仕様書をひも解いていきます。仕様書読んだらわかるだろ?そうなん?あれだけで瞬時に理解しきれるとか頭良すぎるでしょ。あーた。 cmapテーブルはテーブルデータ部とサブテーブルで構成されます。 テーブルデータ部でテーブルデータ数のエンコードレコード構造体が定義されます。まずはテーブルデータ数までの項目について確認すると <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>unsigned short</td> <td>UsVersion</td> <td>テーブルバージョン番号 0 </td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned short</td> <td>usNumTable</td> <td>レコード数</td> </tr> <tr> <td>EncordingRecord</td> <td>EncodingRecord[usNumTable]</td> <td>EncodingRecord構造体をtableの数だけ配列を保持</td> </tr> </table> ■EncodingRecord構造体 <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>unsigned short</td> <td>usPlatformID</td> <td>プラットフォームの番号 ※1 </td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned short</td> <td>usEncodingID </td> <td>プラットフォーム番号によって意味が変わるID</td> </tr> <tr> <td>unsigned int</td> <td>uiOffset</td> <td>サブテーブルが配置されている位置のcmapテーブル先頭からのオフセット位置</td> </tr> </table> プラットフォームIDは全部で5種類。ID2は非推奨で4はCustomなのであまり使われないことを考えると、0と1と3がよく使われる。 ■PlatformID <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; ">ID</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>0</td> <td>Unicode</td> <td>文字コード形式Unicode用</td> </tr> <tr style = " background: #eeeeee;" > <td>1</td> <td>Macintosh</td> <td>アップルのマッキントッシュOS向け</td> </tr> <tr> <td>2</td> <td>ISO</td> <td>標準</td> </tr> <tr style = " background: #eeeeee;" > <td>3</td> <td>Windows</td> <td>マイクロソフトのWindowsOS向け</td> </tr> <tr> <td>4</td> <td>Custom</td> <td>カスタム</td> </tr> </table> ■PlatfomrID=0(Unicode)のときのEncodingID <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; ">ID</th> <th style = "width: 250px; ">Name</th> <th>説明</th> </tr> <tr> <td>0</td> <td>Unicode1.0</td> <td>非推奨</td> </tr> <tr style = " background: #eeeeee;" > <td>1</td> <td>Unicode1.1</td> <td>非推奨。IMPACT.ttfは利用</td> </tr> <tr> <td>2</td> <td>ISO/IEC 10646</td> <td>非推奨。</td> </tr> <tr style = " background: #eeeeee;" > <td>3</td> <td>Unicode2.0 BMPのみ</td> <td>cmap format(0,4,6)</td> </tr> <tr> <td>4</td> <td>Unicode2.0 フルレパートリー</td> <td>cmap format(0,4,6,10,12)</td> </tr> <tr style = " background: #eeeeee;" > <td>5</td> <td>Unicode 異体字制御</td> <td>cmap format(14)</td> </tr> <tr> <td>6</td> <td>Unicode フルレパートリー</td> <td>cmap format(0,4,6,10,12,13)</td> </tr> </table> ■PlatfomrID=1(Macintosh)のときのEncodingIDは0のみ。 ■PlatfomrID=2(ISO)のときのEncodingIDは0,1,2。 0 は 7bitASCIIエンコード。 1 は ISO10646エンコード。2 は ISO8859-1エンコード ■PlatfomrID=3(Windows)のときのEncodingID <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; ">ID</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>0</td> <td>Symbol</td> <td>記号</td> </tr> <tr style = " background: #eeeeee;" > <td>1</td> <td>Unicode BMP</td> <td></td> </tr> <tr> <td>2</td> <td>ShiftJIS</td> <td></td> </tr> <tr style = " background: #eeeeee;" > <td>3</td> <td>PRC</td> <td></td> </tr> <tr> <td>4</td> <td>Big5</td> <td>cmap format(0,4,6,10,12)</td> </tr> <tr style = " background: #eeeeee;" > <td>5</td> <td>Wansung</td> <td></td> </tr> <tr> <td>6</td> <td>Johab</td> <td>cmap format(0,4,6,10,12,13)</td> </tr> <tr style = " background: #eeeeee;" > <td>7-9</td> <td>予約</td> <td></td> </tr> <tr> <td>10</td> <td>Unicode フルレパートリー</td> <td>cmap format(0,4,6,10,12,13)</td> </tr> </table> ■PlatfomrID=4(Custom)のときのEncodingIDは0~255。 OpenTypeFont WindowsNTの互換性マッピング サブテーブルには定義されているNumTableの数だけ以下のようなデータが続きます。その形式は、PlatformIDとEncodingIDの組み合わせで有効なものが使われますが、その形式についてはサブテーブル自身が宣言するものです。0~14の中から0,2,4,6,8,10,12,13,14の9種類のフォーマットがあります。cmap formatと呼びます。IMPACT.ttfは1番目のテーブルがPlatformID=1, EncodingID=0(固定)でformat=0(1バイト文字に適したフォーマット)と2番目のテーブルがPlatformID=3, EncodingID=1(Unicode BMP)でformat=4(疎に分布された2バイトフォント向け)となっていました。 まずは、IMPACT.ttfが使用している。format0,4についてテキスト化したものをリンクにしておきます。 [[メディア:IMPACT TAG cmap TebleInfo.txt|IMPACT_TAG_cmap_TebleInfo.txt]] 以下にすべてのフォーマットについて記述していきますが、特に使われやすいものから記述していくつもりです。まずは0と4と12(Unicodeフル)と14(Unicode異体字制御)の4テーブルについて記述したいと思います。 ===== ■Format0 ===== <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>unsigned int</td> <td>usFormat</td> <td>0 フォーマット番号</td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned int</td> <td>usLength</td> <td>サブテーブルの長さ</td> </tr> <tr> <td>unsigned int</td> <td>usLanguage</td> <td>言語コード番号</td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned char</td> <td>ucGlyphIndex[256]</td> <td>配列番号が文字コードで、その値がグリフ番号となる形式。</td> </tr> </table> ===== ■Format4 ===== <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>unsigned int</td> <td>usFormat</td> <td>4 フォーマット番号</td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned int</td> <td>usLength</td> <td>サブテーブルの長さ</td> </tr> <tr> <td>unsigned int</td> <td>usLanguage</td> <td>言語コード番号</td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned short</td> <td>usSegCountX2</td> <td>セグメント数の2倍の値</td> </tr> <tr> <td>unsigned int</td> <td>usSearchRage</td> <td></td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned short</td> <td>usEntrySelector</td> <td></td> </tr> <tr> <td>unsigned int</td> <td>usRangeShift</td> <td></td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned short</td> <td>usEndCode[unSegCountX2/2]</td> <td></td> </tr> <tr> <td>unsigned int</td> <td>usReservePad</td> <td>予約=0</td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned short</td> <td>usStartCode[unSegCountX2/2]</td> <td></td> </tr> <tr> <td>unsigned int</td> <td>usIdDelta[unSegCountX2/2]</td> <td></td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned short</td> <td>usIdRangeOffset[unSegCountX2/2]</td> <td></td> </tr> <tr> <td>unsigned int</td> <td>usGlyphIndexArray[Variables]</td> <td>要素数はテーブルの長さのあまり分</td> </tr> </table> Format4は疎な文字コード領域毎にグリフIDを付与する方式です。例えばUnicode文字コード0x20~0x7fは連番でGlyphIDの3から156に対応して、次の区画の…と繰り返して定義していくような感じです。但し、文字コードに対応するGIDの算出方法はもう少し複雑な内容になります。SearchRangeとかEntrySelectorとかrangeShiftは、header部分でもやったような処理になっています。 例えばセグメントが以下のように定義されていて <Syntaxhighlight2 lang="text"> Element EndCode StartCode idDelta idRangeOffset ==================================================================== 0x0000( 0) 0x007e 0x0020 0xffe3 0x0000 0x0001( 1) 0x017f 0x00a0 0x0000 0x00c2 0x0002( 2) 0x0192 0x0192 0xff14 0x0000 … … 0x0061( 97) 0xffff 0xffff 0x0001 0x0000 GlyphIndexArray Value ==================================================== GlyphIndexArray[0x0000(00000)]:0x00ac( 172) … GlyphIndexArray[0x002c(00044)]:0x00cf( 207) … </Syntaxhighlight2> 文字コードGlyphIDの変換には大きく2とおりの決定方法があります。まず一つ目の方法でみつける方式の例として、文字コード0x20について見てみます。 0x20がEndcodeの値より小さいことが成立する最大のエレメント番号をみつけます。今回の場合は7eより小さいということでElement番号 0 が対象になります。そして、そのときのStartCodeは0x20で0x20がStartCodeの値より同じ、あるいは、大きいかを比較して成立しない場合は、GIDは 0 になります。今回は成立するので、次の手順に進みます。次は以下の演算を行います。(算出したい対象の文字コード:0x20)-(StartCode:0x20) + (idDelta:0xffe3) & 0xFFFFの値を算出します。今回の場合0x0003がその結果になるのでGID3に文字コード0x20の文字の形が格納されていることを意味します。 もうひとつの計算方法はidDeltaが00となっているのエレメントが計算対象になる文字コードです例えば 0xa0の文字コードだとidDelta=00が対象になります。最初の計算方法と同じように、0xa0がEndcodeの値より小さいことが成立する最大のエレメント番号をみつけます。今回の場合は17fより小さいということでElement番号 1の行が対象になります。そして、StartCodeとくらべて同じか大きいなら、次の演算をします。(算出したい対象の文字コード:0xa0)-(StartCode:0xa0)= 0 + (idRangeOffset:c2を計算します。idRangeOffsetがc2のところからc2だけ進んだところにある番号がGIDになります。セグメントになっているエレメントは全部で0x61まであるので、エレメント総数:0x97 - idRageOffsetのエレメント番号位置:0x1=0x96。そうすると(idRangeOffset:c2)-(算出した値:0x96)=2C。GlyphIndexArrayの配列番号2Cの値が0x00cf(207)がGlyphIDになります。 ちょっと複雑ですが、cmapのformt4はこのように利用する形式です。 次は12と14ですね。やだな。もう疲れたよ。後回しにするか… ===== ■Format12 ===== <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>unsigned short</td> <td>usFormat</td> <td>12 フォーマット番号</td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned short</td> <td>usReserved</td> <td>予約 0</td> </tr> <tr> <td>unsigned int</td> <td>uiLength</td> <td>長さ</td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned int</td> <td>usLanguage</td> <td>言語コード</td> </tr> <tr> <td>unsigned int</td> <td>uiNGroups</td> <td>グループ数</td> </tr> </table> 以下のテーブルがuiNGroupsの数だけ続きます。 <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>unsigned int</td> <td>uiStartCharCode</td> <td></td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned int</td> <td>uiEndCharCode</td> <td></td> </tr> <tr> <td>unsigned int</td> <td>uiStartGlyphCode</td> <td></td> </tr> </table> ===== ■Format14 ===== UVSはUnicode Varidation Sequences Unicode選択値制御=異体字セレクタの略です。Format14は異体字用コードを扱うGlyphID検出方式です。 <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>unsigned short</td> <td>usFormat</td> <td>14 フォーマット番号</td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned int</td> <td>uiLength</td> <td></td> </tr> <tr> <td>unsigned int</td> <td>uiNumVarSelectorRecords</td> <td></td> </tr> </table> 以下のテーブルがuiNumVarSelectorRecordsの数だけ続きます。 <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>unsigned int</td> <td>uiVarSelector</td> <td></td> </tr> <tr style = " background: #eeeeee;" > <td>unsigned int</td> <td>uiDefaultUVSOffset</td> <td></td> </tr> <tr> <td>unsigned int</td> <td>uiNonDefaultUVSOffset</td> <td></td> </tr> </table> ■Default UVS Table ■Default UVS Table header <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>unsigned int</td> <td>uiNumUnicodeValueRanges</td> <td></td> </tr> </table> ■Unicode Value Range <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>Uint 3byte</td> <td>Ui3StartUnicodeValue</td> <td></td> </tr> <tr style = " background: #eeeeee;" > <td>Unsigned char</td> <td>ucAdditionalCount</td> <td></td> </tr> </table> ■NonDefault UVS Table ■Default UVS Table header <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>unsigned int</td> <td>uiNumUVSMappings</td> <td></td> </tr> </table> ■Unicode Value Range <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: 200px; ">型</th> <th style = "width: 200px; ">Name</th> <th>説明</th> </tr> <tr> <td>Uint 3byte</td> <td>Ui3UnicodeValue</td> <td></td> </tr> <tr style = " background: #eeeeee;" > <td>Unsigned short</td> <td>usGlyphID</td> <td></td> </tr> </table> ==== fpgm ヒント系 ==== Font '''p'''ro'''g'''ra'''m'''の略です。中身はヘッダ定義された位置から、その長さまでが1バイトで表されたフォントプログラム命令(TrueType命令とかOpenType命令、TrueType Instruction ... というワードで検索すると対象の文献にたどり着ける)。多くの異なるプログラムから参照されるプログラムになっています。この後に記述するprepやグリフの中に埋め込まれるモノも同じような仕組みを使います。fpgmは関数化されたプログラムを配置するのが主な用途です。最初に関数番号がプッシュされ、関数定義されるたびにスタックからポップされていきます。関数の中でスタックにプッシュした値はポップで使い切らないと関数番号がおかしなことになります。 プログラムの動作の流れは、文字を表示する前にprepに格納されたプログラムで初期化、各グリフに埋め込まれたFont Programが制御点の総数を管理しつつも、fpgmテーブルに格納された関数を番号を指定して呼び出す。各プログラムはcvtテーブルの内容に対して数値を書き出したり、読み込んだりという処理をするという流れです。 工夫をすればわりといろいろなことが出来るプログラムですが、基本的にはフォントの形を微調整するのに使われることが多いです。極端な話これでフォントが使われている環境次第で動作を大きく変えるようなフォントを作ることで、その環境を調べることもできます。各アプリケーションがどういうふうにフォントを扱おうとしているかということも調べれるという感じです。世界には意外とフォントプログラムでそういうことをやっている人がいて、感心させられました。 自分は仕様書のバイトコードと命令文の対応表から逆アセンブルしてどういうプログラムかを見渡すことくらいしかできませんでした。命令以外にも命令を先頭として、命令につづく数バイトをデータとして指定するようなこともあります。 IMPACT.ttfでは以下のようなFont programを保持していました。 [[メディア:IMPACT TAG fpgm TebleInfo.txt|IMPACT_TAG_fpgm_TebleInfo.txt]] 前半が単純なバイトコードの羅列で後半に逆アセンブルした情報が記載されています。関数が60ほど用意されていて、最初のスタックへのプッシュで関数番号のデータを積み上げています。関数番号は関数定義をするFEDFが登場する都度スタックから関数番号を取り出すポップ処理を行います。関数毎の処理については、いまのところでは理解しきれないので、解説しません。 環境に対応するべくフォントの見栄えを変更するものですが、これはほとんどの場合、フォントヒンティングという動作のためにあります。文字が小さくなると、ドット境界をうまく利用するような文字の形へと極端に変更することで視認性を上げています。Windowsでは現代においても画素のあらいディスプレイが使われている可能性が高く、いわゆる低DPIのディスプレイが使われる可能性を考慮しています。MacOSはハードウェアをアップルが独占して制作している関係で、現代において低DPIがほとんど排除されているため、OSのバージョンによって、Fontprogramそのものを無視していることもあるそうです。 つまりFontProgramが全く動作しない環境も多いということです。動作しないからといって、Fontに関してだけで言えば行き詰まることはないです。ちょっと字がみにくいから字を大きくして対処しようとするはずです。あるいはフォントを変えるとかです。フォントによってはヒンティング要素であるFont programがないために低DPIでは見づらいということもあり得ます。 FontForgeでもFont programの動作を確認する処理部分はあります。フォント一覧画面からヒントのfpgmテーブルを確認とすると自分も上記に貼り付けたような逆アセンブル情報が表示されますし、特定のフォントを閲覧するビューにはデバッグ画面もついています。ヒントのデバッグを選択すると画面のDPIを選択してヒントのためのプログラムが動く様子を確認できます。選択したDPIによってフォントの形が変わるという面白い動作があることも確認できます。FontForgeすげぇ。デバッグできる機能まであるとは。点が移動していくプログラム。複雑だぜ。 仕様書は公式にあります。現時点では以下のようなアドレスになっていました。 [https://developer.apple.com/fonts/TrueType-Reference-Manual/RM05/Chap5.html https://developer.apple.com/fonts/TrueType-Reference-Manual/RM05/Chap5.html] [https://docs.microsoft.com/en-us/typography/opentype/spec/tt_instructions https://docs.microsoft.com/en-us/typography/opentype/spec/tt_instructions] 公式のフォント関連の情報の多さをみるだけでも複雑すぎることがうかがい知れる。これに少しでも対峙しようとした私たちは偉いのかもしれない。それを亡き者にしようとするアップル RetinaDisplay 高DPIが、低DPIの高度な技術を消し去るとはものすごいな。せっかく考えた技術なので無くなりはしないのだろうけど。これだけでもフォント専門学校作れるくらいの技術だな。全部理解するのに3年とかかかりそう。そしてさほど役に立たないかもしれない未来。そりゃ伝統技術も息絶えるわけだな。覚えるのにものすごく時間かかるのに、さほど必要とされていない未来。よく似てる。でも確かに存在する現代の職人。君の事だ。お金にはならないが、この知識。有意義だと思う。 [https://nixeneko.hatenablog.com/entry/2020/02/04/000000 https://nixeneko.hatenablog.com/entry/2020/02/04/000000] 上記サイトの管理人はtruetype命令で、回転、pixel/em、pointSize、ランダム輪郭といったことをするフォントを作ってしまっています。font programを使いこなしてる。フォントヒンティングのためにあるから、出来ないこともあるという感じのことが伺えます。すごいね。 ==== prep ヒント系 ==== '''preP'''rogramの略です。一度だけ実行されるプログラムです。fprgの命令の前に実行されるもののようです。 IMPACT.ttfの結果は以下とおりです。 [[メディア:IMPACT TAG prep TebleInfo.txt|IMPACT_TAG_prep_TebleInfo.txt]] ==== cvt ヒント系 ==== Control Value Table は 制御値テーブルで prep や fpgm や グリフの中のFont Programで使われる制御値をまとめたテーブルです。このテーブルは Font Programで追加・削除・編集される可能性があるため、初期値のようなものです。 公式では4バイトの数値となっていますが、実際は2バイトの数値のタグテーブル部で記述されたサイズの配列となっているように見えます。FontForgeも2バイトで扱っているようです。 2バイトで扱った場合のIMPACT.ttfの結果が以下のとおりです。 [[メディア:IMPACT TAG cvt TebleInfo.txt|IMPACT_TAG_cvt_TebleInfo.txt]] ==== loca ==== glyfタグテーブルのそれぞれのGlyph ID毎のglyfタグテーブル開始位置からのOffset値を順に格納しています。次のOffset値との差分が、そのGlyph IDの長さになります。Glyph ID [0] ~ Glyph [最後のID番号-1]の数のOffsetがあります。Glyph [最後のID番号]には次のテーブルが始まるOffset番号になっていて、この番号とGlyph [最後のID番号-1]の差分で最後のIDの長さも取得できるようになっています。Offset値の記述形式となる型は16bit整数のunsigned short と 32bit整数のunsigned intの2種類があり、どちらが使われるかはheadタグテーブルのindexToLocFormat値が0なら16bit、1なら32bitとなります。 IMPACT.ttfの結果は以下のようになっています。 [[メディア:IMPACT TAG loca TebleInfo.txt|IMPACT_TAG_loca_TebleInfo.txt]] ==== glyf ==== グリフの形状を記述した核となるテーブルがglyfタグテーブルです。glyfはGlyphのことです。以下のような構造の可変長のテーブルになっています。 == '''関連記事''' == :[[フォント OpenType 構造解析]] : [[FreeTypeをコンパイル]] :[[FreeTypeを使う]] [[フォント]]に戻る。
フォント TrueType 構造解析
に戻る。
個人用ツール
ログイン
名前空間
ページ
議論
変種
表示
閲覧
ソースを表示
履歴表示
操作
検索
案内
メインページ
コミュニティ・ポータル
最近の出来事
最近の更新
おまかせ表示
ヘルプ
ツールボックス
リンク元
関連ページの更新状況
特別ページ