# スプラインフォントデータベース

このページは悲しくなるほど時代遅れです。これは2005年12月13日に事実だったことの大まかな近似です。時代遅れであっても、これは役に立つでしょうが、現在のフォーマットについて本当に知りたい場合は sfd.c を参照して、それがどのように読み込みを行うかを調べてください。いくつかの秘教めいた機能の説明は完全ではありませんが、あなたが (とくに sfd.c を調べた後に) フォーマットを記述できるようになるためのヒントとなることを私は望んでいます。

FontForge の sfd ファイルは ASCII ファイルです (なのでそれらは Internet を介して簡単にコピーでき、diff を取ることには何らかの異義があります。それにはあなたのフォントの完全な記述が含まれます。

それらはかすかに BDF ファイルから範をとっています。最初のごくわずかな行にフォント全体の属性が含まれ、それに続いて各文字のセクションが続き、最後に各ビットマップフォントのセクションがきます。

- フォントヘッダ
- アウトライン文字データ
- ビットマップフォント
- CID キー指定フォント
- マルチプルマスターフォント
- 自動保存フォーマット

警告: ある SFD ファイルから他のファイルへ情報をカット&ペーストしたいという誘惑を覚えます。これは大抵の場合は問題ありませんが、これを避けなければならない場合が 2 つあります:

- TrueType 命令を含むグリフをコピーした場合、それらの命令が古いフォントには定義されていても新しいフォントには未定義のサブルーチンを呼んでいる可能性があります。グリフがグリッド合わせを行ったとき、予想外の事柄 (システムクラッシュを含む) が起こる可能性があります。
- 置換 (合字、カーニング、連鎖型文脈依存、…) をあるフォントから別のフォントにコピーしたときには、置換にはフォントに保存されているスクリプト/言語テーブル内のインデックスが保存されています。それらのテーブルが一致していなければ、悪い事 (FontForge のクラッシュ) が起こるかもしれません。
- グリフインデックス (これはフォント語とに異なります) によって指定された参照を含むグリフをコピーすると、間違ったグリフを参照する結果となるでしょう。

### フォントヘッダ

ここに示すのは、最初のごく僅かな行がどのような感じかを示す例です (このセクションでは、順番はほとんど意味をもちません):

>     SplineFontDB: 1.0
>     FontName: Ambrosia
>     FullName: Ambrosia
>     FamilyName: Ambrosia
>     Weight: Medium
>     Copyright: Copyright (C) 1995-2000 by George Williams
>     Comments: This is a funny font.
>     Version: 001.000
>     ItalicAngle: 0
>     UnderlinePosition: -133
>     UnderlineWidth: 20
>     Ascent: 800
>     Descent: 200
>     DisplaySize: -24
>     AntiAlias: 1
>     WinInfo: 64 16 4
>     FitToEm: 1
>     XUID: 3 18 21
>     Encoding: unicode
>     Order2: 1
>     OnlyBitmaps: 0
>     MacStyle: 0
>     TeXData: 1 10485760 0 269484 134742 89828 526385 1048576 89828

最初の行は、単にこのファイルが SFD ファイルであることを示すだけのものです。その下の 3 行は、PostScript でフォントに設定することができる各種の異なる名前を示しています。それに続く項目群は、まったくその名の通りに用いられます (意味が分からない場合は、フォント情報ダイアログで調べてみてください)。2, 3 の項目にはちょっと説明が必要でしょう:

TeXData
  これらは TeX のフォントパラメータ (およびいくつかの同種の情報) です。最初の数値は 1, 2 または 3 で、フォントがテキスト、数学または数学拡張フォントのどれであるかを示します。次の数値はデザインポイントサイズ (×(1<<20)) です。その後にフォントパラメータが続きます。これらの数値は通常 TeX の fix_word フォーマットで表されます。このフォーマットでは 2 進数で先頭 20 桁目に小数点が来ます (ですから、実際の数値を得るためには (1<<20) で割ってください)。
DisplaySize
  これは、フォントビュー内でフォントを表示する際のデフォルトとして用いられる、1 em あたりのピクセル数です (もちろん変更可能です)。負の数字は、アウトラインをラスタライズして表示することを意味し、正の数字は、そのサイズに一致する作成済みのビットマップを使用することを意味します。
AntiAlias
  フォントビューで、フォントをアンチエイリアス表示するか、白黒表示するか。(アンチエイリアスの方がきれいに表示されますが、遅くなります)
FitToEm
  このフォントを表示するフォントビューで、`表示を全角に固定(F)` にデフォルトでチェックを入れておくか。
WinInfo
  このフォントを表示するウィンドウのデフォルト画面を表す 3 つの値です。最初の値は、ウィンドウは符号位置 64 にあるグリフが見えるようにスクロールするかを表し、2 番目の値は、ウィンドウが横幅 16 文字分の欄をもつかどうかを、最後の値は建てに 4 文字分の欄を持つかどうかを表します。
Encoding
  普通のフォントでは、これは `エンコーディング(E)` プルダウンリストに表示される名前のどれかと同じ (か、それに非常に近い) ものとなるでしょう。CID キー指定フォントは、Encoding 行を含まず、以下のようなものが含まれるでしょう。

>     Registry: Adobe
>     Ordering: japan1
>     Supplement: 4
>     CIDVersion: 1.2

フォントによっては、いくつかの TrueType 情報もここに含まれるでしょう (それらの意味については TrueType の仕様書を参照してください。それらは大抵 OS/2, hhea, vhea テーブルのいずれかにあるはずです。

>     FSType: 4
>     PFMFamily: 17
>     TTFWeight: 400
>     TTFWidth: 5
>     Panose: 2 0 5 3 0 0 0 0 0 0
>     LineGap: 252
>     OS2LineGap: 252
>     VLineGap: 0
>     OS2Vendor: 'PfEd'
>     OS2FamilyClass: 2050

以下の項目は OS/2 および hhea テーブルからも取得されますが、それらは僅かにより複雑です。それらのキーワードは対になっているので `HheadAscent` と `HheadAOffset` は一緒に動作します。*Offset キーワードが 1 (真) である場合、もう片方のキーワードは、FontForge が正しい値として認識する値を基準とした相対値として扱われます。その場合 FontForge は適切と思われる値を計算して、それにキーワードで指定された値を加えます。ですから以下の例では、FF は TrueType フォントの OS/2 テーブルに格納された値を得るために `HheadAscent` に“0”を加えるべきと考えます。その一方、Offset フラグが 0 (偽) に設定されている場合、アセントの値は指定されたとおりの物が使用されます。

>     HheadAscent: 0
>     HheadAOffset: 1
>     HheadDescent: 0
>     HheadDOffset: 1
>     OS2TypoAscent: 0
>     OS2TypoAOffset: 1
>     OS2TypoDescent: 0
>     OS2TypoDOffset: 1
>     OS2WinAscent: 0
>     OS2WinAOffset: 1
>     OS2WinDescent: 0
>     OS2WinDOffset: 1

OS/2 テーブルには下付き文字、上付き文字および取り消し線の位置情報が含まれています:

>     OS2SubXSize: 1351
>     OS2SubYSize: 1228
>     OS2SubXOff: 0
>     OS2SubYOff: -446
>     OS2SupXSize: 1351
>     OS2SupYSize: 1228
>     OS2SupXOff: 0
>     OS2SupYOff: 595
>     OS2StrikeYSize: 143
>     OS2StrikeYPos: 614

MacStyle フィールドは、(存在すれば) そのフォントがボールド、イタリック、コンデンスト、エクステンディドなどに該当するかどうかを示します。

一部のフォントは、Private 辞書に含まれる PostScript 固有の情報をもっています。

>     BeginPrivate: 1
>     BlueValues 23 [-19 0 502 517 750 768]
>     EndPrivate

フォントに OpenType 機能が含まれているならば、用字系・言語項目のリストもあるはずです:

>     ScriptLang: 3
>      1 latn 1 ROM
>      1 latn 4 DEU  ROM  VIT  dflt
>      3 cyrl 1 dflt grek 1 dflt latn 5 DEU  ROM  TRK  VIT  dflt

最初の行は、用字系・言語項目が 3 セット存在することを示し、その後の 3 行にそれらの項目が含まれます。2 行目は、この項目が有効になるのがただ 1 個の用字系 (‘latn’) のみで、なおかつ言語が‘ROM ’であるときに限られることを示します。その次の行も 1 個の用字系のみに対して有効であることを示しますが、今度は 4 個の言語 (‘DEU ’,‘ROM ’,‘VIT ’またはデフォルト言語) に対して適用されることを表します。最後の行では、複数の用字系と複数の言語において有効となる項目の例を示しています。

OpenType 機能はこのリスト内のインデックスを用いて格納されます。この場合、ある機能がインデックス“0”であるならば、その機能はルーマニア語のラテン文字表記のときにのみ有効になります。インデックスが 2 であるならば、その機能はキリル文字・ギリシャ文字およびラテン文字に対して有効になるわけです。その機能が「入れ子」になった物であることを表すための特別な用字系インデックスとして、65535 を使っています。これはそれ自体で起動されることは決してなく、文脈依存または文脈依存連鎖の照合 (これ自体は、独自の用字系・言語インデックスを備えています) によって起動が制御されるものです。

フォントに何らかのカーニングクラスが含まれていれば、

>     KernClass: 31 64 2 0
>      1 F
>      41 L Lacute glyph78 Lcommaaccent Ldot Lslash
>      1 P
>     ...
>      6 hyphen
>      5 space
>     ...
>      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
>      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -152 -195 -152 -225 0 0 0 0 0 0 0 0 0 0 0 0 0 -145 -145 -130
>      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -130 0 0 0 0 0 0 0 0 0 0 -145 0 -115 0 0 0 0 -65 0 -140 -120 -120
>     ...

最初の行は、このカーニングクラスに含まれる先頭文字のクラスが 31 種類存在し、第二文字のクラスが 64 種類存在することを表しています。これは、上記の用字系・言語リストの項目 2 に対して有効になります。OpenType フラグ は 0 となります。次の行は、最初の文字 (クラス 0 は予約済みで、通常は定義する必要がないので、この番号は 1 となります) の先頭文字クラスは文字“F”1 文字からなることを表します (“F”の前にある数字は行の文字数です。これは SFD ファイルの処理速度の向上に役立ちますが、それ自体で意味を持つ情報ではありません)。次の行は、先頭文字のクラス 2 で、より多くの文字を含んでいるため文字列長も長くなっています。30 個の項目が続いた後に、第二文字のクラスが始まります。これは、先頭文字のクラスと全く同様です。第二文字のクラスを全部定義し終わった後に、多数(正確には <先頭文字クラスの個数×第二文字クラスの個数>) の数値からなる 1 個の配列が来ます。これは、該当するクラスの対における左右の文字間に施されるカーニングの量を指定しています (例えば、文字1 が先頭文字クラス 2 に属し、文字2 が第二文字クラス 4 に属している場合、この配列のインデックス 3×<文字2 のクラス番号> + 4 で指定することになります)

お使いの FontForge がデバイステーブルサポートつきの設定でコンパイルされている場合、デバイステーブルがカーニングオフセット配列の間に組み込まれているのが見つかるでしょう:

>     ...
>     0 {} 0 {} 0 {} ...
>     -145 {12-13 -1,1} -145 {} -130 {8-9 -1,-1} ...

GPOS/GSUB テーブルに含まれる OpenType 機能の順番も保存することができます:

>     TableOrder: GPOS 4
>     	'subs'
>     	'sinf'
>     	'mark'
>     	'kern'
>     TableOrder: GSUB 2
>     	'frac'
>     	'nutf'

フォントに TTF のヒント情報が含まれている場合、ファイルには TrueType テーブルを解析しないで格納することができます (TTF のヒントを理解することは FontForge の能力を超えていますが、少なくともデータを保存することはできます):

>     TtfTable: prep 4360
>     5S;o3()It?eJ8r@H[HSJH[H^@!b&BQ*?Vcm@'XSh+1MACZ>Up/\,o1+Ca't2!<ocH+Wn2p"@,t&
>     +Wo+[()Is6G8:u7D/^7,*,KO/(E=N5!=s)LCMjn,:Mp3:DSL&j05dG#cY`hLCN"!<CBO$@s(_ZX
>     ...

最初の行は、‘prep’テーブルの長さが 4360 バイトであることを表します。後ろに続く行には、4360 バイトのデータが ASCII85Encode1 (入力されたバイナリデータをあまりサイズを大きくしないで ASCII にパックします。この方式の説明は、PostScript リファレンスマニュアル (第3版、原書 131〜132 ページ) を参照するか、`$ man btoa` で調べてください) にパックされて納められています。

TrueType の name テーブルは複数の `LangName` 項目によって表されます: 数字は言語を表し、その後ろに続くのは UTF-7 で符号化された文字列のリストです。最初の文字列は ID=0 (著作権) に対応し、2 番目は ID=1 (ファミリー) に対応し、…という具合で、末尾にある空文字列はすべて省略されます。アメリカ英語 (1033) のセクションでは、これらの名前のどれかが、等価な PostScript 項目と正確に一致している場合、その名前は省略されます (これにより更新の取扱いが簡単になり、ユーザは 1 箇所で著作権表示を変更するだけでよくなります)。

>     LangName: 1033 "" "" "Regular" "GWW:Caliban Regular: Version 1.0" "" "Version 1.0"
>     LangName: 1032 "" "" "+A5oDsQ09A78DvQ05A7oDrAAA"

フォントに何らかのアンカークラスが含まれている場合:

>     AnchorClass: "top" mark 4 7 1 "bottom" mark 4 7 1 "Anchor-2" mark 4 7 1 "Anchor-3" mark 4 7 2 "Anchor-4" mark 4 7 2 "Anchor-5" mark 4 7 3 "Anchor-6" mark 4 7 4

ここには“top”という名前で、機能タグ“mark”を含み、OpenType フラグが 4 で、用字系/言語インデックスが 7 であるアンカークラスが存在し、これが“1”と印づけられた他のアンカークラスと併合すべきであることを示します。次のクラスは“bottom”という名前で、その次は“Anchor-2”という名前で、以下同様に続きます。(アンカークラス名は UTF-7 で出力されます)

文脈依存または文脈依存連鎖の照合も、フォントヘッダに格納されます。それらはキーワード“ContextPos”,“ContextSub”,“ChainPos”,“ChainSub”または“ReverseChain”で始まり、キーワード“ENDFPST”で終了します。文脈依存の照合は現在位置にあるグリフ列を所定の文字列群と照合することしかできませんが、文脈依存連鎖の照合は現在のグリフ、および先読みグリフだけでなく先行するグリフをチェックすることができます (これをバックトラックといいます)。このフォーマットには 4 種類あります。
適用範囲テーブルによる方法

>     ChainSub: coverage 0 0 'abvs' 0 0 0 1
>      1 1 0
>       Coverage: 7 uni0C40
>       BCoverage: 8 glyph388
>      1
>       SeqLookup: 0 '0013'
>     EndFPST

これは適用範囲クラスによる単純文脈連鎖依存の置換を定義しています。OpenType フラグは 0, 用字系/言語インデックスは 0 で、機能タグは‘abvs’です。クラスもバックトラッククラスも先読みクラスも定義されていません (適用範囲テーブルで指定しています)。ルールが 1 個あります (これらの暗号のようなコメントのより詳しい説明については、OpenType 仕様書の、文脈依存照合 (contextual lookup) について述べた箇所を調べてください)。

その後に最初のルールが続きます。1 行目の“1 1 0”というのは、何個の適用範囲テーブルが通常リスト (1 個)、バックトラックリスト (1 個) および先読みリスト (0 個) が含まれているかを表します。その次にあるのが 1 個の通常適用範囲テーブルで、これは 1 個のグリフ (uni0C40) を記述しています。続いて 1 個のバックトラック適用範囲テーブルがあり、これも 1 個のグリフ (glyph388) を定義しています。最後にあるのが 1 個の連鎖型照合で、通常位置 0 において‘0013’という名前の置換を適用する必要があることを表します。

一言で言うとこうなります: グリフの連鎖“glyph388 uni0C40”が見つかったら、それはこの照合に一致し、その時は (よそで定義されている) 置換‘0013’を uni0C40 に適用すること。

クラスによる方法

>     ChainSub: class 0 0 'calt' 3 3 0 1
>       Class: 52 b o v w b.high o.high v.high w.high r.alt.high r.alt
>       Class: 43 a c d e f g h i j k l m n p q r s t u x y z
>       BClass: 52 b o v w b.high o.high v.high w.high r.alt.high r.alt
>       BClass: 43 a c d e f g h i j k l m n p q r s t u x y z
>      1 1 0
>       ClsList: 2
>       BClsList: 1
>       FClsList:
>      1
>       SeqLookup: 0 'high'
>     EndFPST

これは、クラスによる文脈連鎖型置換を 1 つ定義しています。最初の行のフォーマットは上で説明したのと同じです。ここでは通常の一致に対する 3 つのクラスとバックトラックによる一致に対する 3 つのクラスが定義されています。その後ろの 4 行はクラスを定義しています。クラスによるカーニングの場合と同じく、クラス 0 は明示的に定義する必要はなく、「他のクラスのどれにも定義されていない任意のグリフ」として暗黙に定義されます。そこで、クラス 1 を“b,o,v,…”と定義し、クラス 2 を“a,c,d,e,…”と定義することになります。次に、クラス群のバックトラックを定義します（ここでは通常の一致のためのクラスとたまたま同じですが、常にそうであるわけではありません)。

ルールの 1 つでは、通常クラス 2 に含まれる何かの後にバックトラッククラス 1 が来た場合 (つまり、“ba”や“oc”のような何らかの文字列がある場合) 置換‘high’を適用しています。

グリフによる方法

>     ChainSub: glyph 0 1 'calt' 0 0 0 1
>      String: 1 D
>      BString: 3 c b
>      FString: 1 e
>      1
>       SeqLookup: 0 'rigl'
>     EndFPST

この例でも 1 個のルールが定義されています。このルールでは、グリフの連鎖“c b D e”が存在した場合、置換‘rig1’をグリフ“D”に適用するように指示しています。

最後は、逆順の適用範囲テーブルによる方法です。

>     ChainSub: revcov 0 0 'foo ' 0 0 0 1
>      1 1 0
>       Coverage: 7 uni0C40
>       BCoverage: 8 glyph388
>      1
>       Replace: 11 uni0C40.alt
>     EndFPST

これは、グリフ 388 の前に uni0C40 が来た場合、uni0C40 を uni0C40.alt に置き換えるべきであることを表しています。

Apple 状態機械を含めることができます。それはキーワード“MacIndic”,“MacContext”,“MacInsert”または“MacKern”で始まり、“EndASM”で終了します。

>     MacContext: 2,2 16384 9 5
>       Class: 320 yehhamzaabovearabic beharabic teharabic theharabic jeemarabic haharabic khaharabic seenarabic sheenarabic sadarabic dadarabic taharabic zaharabic ainarabic ghainarabic feharabic qafarabic kafarabic lamarabic meemarabic noonarabic heharabic alefmaksuraarabic yeharabic peharabic tteharabic tcheharabic veharabic gafarabic
>       Class: 227 noonghunnaarabic alefmaddaabovearabic alefhamzaabovearabic wawhamzaabovearabic alefhamzabelowarabic alefarabic tehmarbutaarabic dalarabic thalarabic reharabic zainarabic wawarabic ddalarabic rreharabic jeharabic yehbarreearabic
>       Class: 201 shaddakasraarabic shaddakasratanarabic shaddafathaarabic shaddadammaarabic shaddadammatanarabic fathatanarabic dammatanarabic kasratanarabic fathaarabic dammaarabic kasraarabic shaddaarabic sukunarabic
>       Class: 13 tatweelarabic
>       Class: 17 ttehinitialarabic
>      0 0 ~ ~
>      0 0 ~ ~
>      0 0 ~ ~
>      0 0 ~ ~
>      2 32768 ~ ~
>      ...
>      3 32768 'M002' 'M003'
>      ...
>     EndASM

状態機械は、どの Mac 機能/設定の対によって呼び出されるかの定義と、いくつかの Mac フラグおよび機械に含まれる状態の個数を含む行から始まります。 Mac 上の最初の 4 状態は定義済みなので、クラス 4 (yehhamzaabovearabic) から始まることになります。最後に、状態遷移を表す行が <クラスの個数>×<状態の個数> だけの行数にわたって続きます。状態 0, クラス 0 の定義が最初にあり、続いて状態 0, クラス 1 …と続きます。

各状態遷移には、次に移る状態と、一連のフラグが含まれます。そのほかの、状態機械のタイプに依存する引数も置くことができます。

MacIndic | このフォーマットには追加の引数はありません
MacContext | このフォーマットは 2 個の置換の名前を潜在的に含みます。1 個はマーク付きグリフに適用される物で、もう 1 個は現在のグリフに適用される物です (特殊な置換“~”は何もしないことを意味し、プレースホルダとして用いられます。
MacInsert | このフォーマットには 2 個のグリフリストが含まれ、それぞれの前には、後ろに何バイト続くかを表す数値が置かれます。

>     2 0 0 3 a b
>     0 32768 4 fi q 0

最初の行は、マーク付きグリフの箇所には挿入する物がなにも無いが、現在グリフの位置には“a”と“b”を挿入することを表しています。2 行目は“fi”と“q”はマーク付きグリフの位置に挿入され、現在グリフの位置には何も挿入しないことを表します。グリフの前に文字を挿入するか、後ろに挿入するかはフラグによって決まります。

MacKern | このフォーマットはカーニングオフセットのリストを含みます。最初にあるのは個数フィールドで、後ろに何個の数値が続くかを表しており、それに続いて、あらかじめカーニングスタックにプッシュされたグリフのカーニングを調整する数値のリストが置かれます。

項目 GenTags は、FontForge が自分で生成した機能タグのリストを記述します。

>     GenTags: 1 sb'rigl'

この行は、FontForge が 1 個のタグを生成しており、生成されたタグは置換参照に用いられ (sb⇒substitution)、そのタグ名が‘rig1’であることを表しています。

Mac の機能/設定の名前リストを置くことができます。

>     MacFeat: 0 0 0
>     MacName: 0 0 24 "All Typographic Features"
>     MacSetting: 0
>     MacName: 0 0 12 "All Features"
>     MacFeat: 1 0 0
>     MacName: 0 0 9 "Ligatures"
>     MacSetting: 0
>     MacName: 0 0 18 "Required Ligatures"
>     MacSetting: 2
>     MacName: 0 0 16 "Common Ligatures"
>     MacFeat: 2 1 2

フォントの先頭近くに項目 Grid を置くことができます。これはフォントのグリッドレイヤに描画されるスプラインを指定します。スプラインセットのフォーマットの説明については以下を参照してください:

>     Grid
>     678 -168 m 5
>      -40 -168 l 5
>     -678 729 m 1
>      1452 729 l 1
>     -678 525 m 1
>      1452 525 l 1
>     EndSplineSet

### アウトライン文字データ

その次に、非 CID フォントでは、以下のような行が現れます:

>     BeginChars: 285 253

これは、フォントのエンコーディングには 285 文字ぶんの場所が取られており、全部で 253 個が定義済みであることを表します (通常、制御文字は定義されません)。文字は以下のように表現されます:

>     StartChar: exclam
>     Encoding: 33 33 3
>     Width: 258
>     Flags:
>     HStem: 736 13<39 155>  -14 88<162 180>
>     VStem: 71 84<49 396>
>     Fore
>     195 742 m 0
>      195 738 193 736 189 736 c 0
>      175 736 155 743 155 682 c 0
>      155 661 130 249 130 131 c 0
>      130 100 96 99 96 131 c 0
>      96 149 71 662 71 682 c 0
>      71 731 51 736 37 736 c 0
>      33 736 31 738 31 742 c 0
>      31 748 36 747 38 749 c 1
>      188 749 l 1
>      190 747 195 748 195 742 c 0
>     80 32 m 0
>      81 53 95 75 116 74 c 0
>      137 73 150 53 150 32 c 0
>      150 10 137 -14 115 -14 c 0
>      93 -14 79 10 80 32 c 0
>     EndSplineSet
>     EndChar

最初の行では文字名を定義しています。次の行では文字符号を定義していて、最初に現在のフォント内の符号値があり、次に Unicode での符号値がきて、最後にフォント独自の位置 (GID) が来ます。それから、次の行に送り幅が来ます。

その次の行にフラグ文字を並べた文字列が来ます (現在 5 つのフラグが定義されています:“H”⇒ 最後にヒント付けを行って以降文字が変更された、“M”⇒ 文字のヒントが手動で調整された、“W”⇒ 幅がユーザの指定で設定された、および“O”⇒ 最後に保存したときにその文字が開いていた、“I”⇒その文字の命令が最新の状態と一致しない)

次に水平および垂直方向の (PostScript) ステムヒントが来ます (いくつかの 2 個の数値対の集まりで、対の最初の数値はステムの位置を表し、次の数値がステムの幅を表し、角括弧 (<>) で囲まれた数値対はそのヒントがどこで有効かを表します)。

縦書きメトリックを含むフォントでは、縦書きの送り幅を指定する

>     VWidth: 1000

という定義を置くことができます。

項目 `Fore` は前面スプラインの始まりを指定します。それらは PostScript コマンドで表されますが、moveto を m に、curveto を c に、lineto を l (小文字エル) に省略しています。文字の後ろに来る数値はフラグの組で、各ビットには以下のような意味があります。

マスク | 意味
--- | ---
0x3 | その点が曲線上の点 (0) か、角の点 (1) か曲線の開始点 (2) であるかを示します。
0x4 | この点は選択されている
0x8 | この点に、デフォルトの次の制御点が存在する
0x10 | この点に、デフォルトの前の制御点が存在する
0x20 | この点は x 方向に丸められる必要がある (TrueType のヒントづけです。実際には動作しません)
0x40 | この点は y 方向に丸められる必要がある (TrueType のヒントづけです。実際には動作しません)
0x80 | この点は (TTF ファイルからの読み込み時に) 2 個の制御点の中点に 補間されたので、独自の点番号が存在しない
0x100 | この点は決して補間してはならない

TrueType フォント用のスプラインには、フラグの後ろに 2 個の追加の数値が存在します。 点それ自身と、引き続く制御点に対しては TrueType 点番号が振られています。値が -1 の場合は、その点には番号が振られていないことを表します。

ヒント置換を含むフォントのスプラインは、ヒント置換が発生する全ての点の前にヒントマスクが存在します:

>     459 422 m 1xc0
>      339 442 l 1xa0
>      312 243 l 1

ここでは最初の 2 個の点はヒントマスク“xc0”および“xa0”を含みます。これらのマスクはグリフ内のヒントの個数に応じて (ほとんど) 任意の長さを持つことができます。“xc0”は、最初の 2 個のヒント (0x80 と 0x40) が有効になっていることを示し、“xa0”は、最初と 3 番目 (0x80 と 0x20) が有効であることを意味します。

背景に置かれる一連のスプラインもこれ同様ですが、項目 `Back` で始まります。

一方、背景イメージは以下の恐ろしげなフォーマットで格納されます:

>     StartChar: A
>     ...
>     Image: 167 301 0 21 2 1 23 753 2.53892 2.53892
>     J:N0SYd"0-qu?]szzz!!#7`s7cQozzz!!!!(s8Viozzzz"98E!zzzz!!3-"rVuouzzz!!!'"
>     s8N'!zzz!!!!$s8W,7zzzz"98E$huE`WzJ+s!Dz!"],0s6p!g!!!!"s8W-!n,NFg!!!Q0s8Vio
>     z5QCc`s82is!!!!`s8W,gz!WW3"s8W&uzJ,fQKp](9o!!iQ(s8W-!z!<<*!s7cQo!!",@s8W-!
>     ...
>     EndImage
>     EndChar

ここで、Image: 行の各数値はそれぞれ以下の意味をもちます: (画像の) 幅 (ピクセル単位)、高さ、画像のタイプ (0⇒単色、1⇒インデックスカラー、2⇒トゥルーカラー)、1 行あたりのバイト数、カラーテーブル内のカラー項目の個数、カラーテーブル内の透明色のインデックス (トゥルーカラー画像においては透明色そのもの)、画像の左上の x 座標および y 座標、画像ピクセルを文字ユニットに変換するための x, y 方向の拡大率です。それから Adobe の Encode85 フィルタによるバイナリデータの束が続きます (この説明は PostScript リファレンスマニュアルを参照してください)。これらのデータはカラーテーブルに含まれる全ての値と、それに続く画像ピクセルデータのダンプです。

ビットマップデータはランレングスエンコーディングで圧縮されます。これの詳細を説明するつもりはありませんので、それを理解する必要がある場合はファイル sfd.c から image2rle を検索して、どう処理を行っているかを調べることをお勧めします。画像はランレングスエンコーディング (RLE) で圧縮され、上記の形式で出力されます。この場合のみ、“Image:”にはデータストリームから読み込まれるバイト数を表すもう 1 つのパラメータが必要となります。

文字には、必ずしも何らかのスプラインが含まれないとならないわけではありません。

>     StartChar: semicolon
>     Encoding: 59 59
>     Width: 264
>     Flags:
>     HStem:
>     VStem:
>     Refer: 33 44 N 1 0 0 1 0 0 1
>     Refer: 35 46 N 1 0 0 1 0 414 2
>     EndChar

上の例は、他の文字への参照のみを含んでいる一例です (セミコロンを、カンマを描画して、その上にピリオドを載せることによって描画しています)。最初の数値は参照先の文字のグリフインデックス (当然、現在のフォント内での) です。2 番目の数値は Unicode の符号位置で、N は、参照が選択されていないことを表し、それに続く 6 個の数値は PostScript の変換行列を表します。カンマ (Unicode 44) の行列は恒等行列で、ピリオド (Unicode 46) に対する行列は垂直方向に 414 ユニット平行移動しています。最後の数値は TrueType フラグの集合です:

- 1 ⇒ メトリックで使用
- 2 ⇒ グリッドに合わせて丸める
- 4 ⇒ (オフセットでなく) 点の一致による位置参照
  このフラグがセットされている場合、2 個の数字が追加されます。最初の数字は基底グリフ内の点番号で、2 番目の数字は現在の参照における点番号です。

  >     Ref: 33 44 N 1 0 0 1 0 0 1
  >     Ref: 35 46 N 1 0 0 1 0 414 6 3 7 O

  最後の行は、点 3 と点 7 が一緒には位置されることを示しています。最後の省略可能な “O”は、この情報が最新の状態と一致しないことを表します。

古い版の SFD ファイルは以下のフォーマットを使っていました:

>     Ref: 44 44 N 1 0 0 1 0 0
>     Ref: 46 46 N 1 0 0 1 0 414

この最初の数値は、被参照要素の符号位置を指定しています。

PostScript のグリフにはカウンタマスクを含めることもできます:

>     StartChar: m
>     Encoding: 109 109 77
>     Width: 785
>     HStem: 0 18<28 224 292 488 566 752> 445 27<280 296 542 558>
>     VStem: 98 56<45 376> 362 56<45 378> 626 56<45 378>
>     CounterMasks: 1 38
>     ...
>     EndChar

この例では、CounterMasks: 行は 1 個のカウンタグループを (最初の引数で) 宣言しています。“38”(およびそれに続く他のすべての値) は、16 進表記のビットマスクで、グループを表しています。ビットマスクのサイズは常に 8 の倍数です (つまり、16 進数は常に偶数桁となります)。マスク内の最上位ビットは、最初のステムヒントが存在する(1) か存在しない(0) かを表します。2 番目の上位ビットは同様に 2 番目のヒントに相当し、以下同様です。どのヒントにも対応しない余計な下位ビットはすべて無視されます。(最下位ビットでなく最上位ビットから始めるのは奇妙だと私も知っていますが、これは Adobe の技術的決定です)。ここでは、3 番目 (0x20), 4 番目 (0x10) および 5 番目 (0x08) のステムヒントがグループ内に存在し、カウンタマスク値は 0x38 となっています。グリフに 4 個の VSTEM ヒントを追加した場合、全部でヒントは 9 個となるので、マスクは 0x3800 となります (9 ビットを格納するには 2 バイト必要だからです)。

フォントが TrueType ファイルから読み込まれた場合、ヒント情報を含めることができます (FontForge は TrueType ヒントを理解しようとは試みず、単に保持するだけです)。

>     TtfInstrs: 107
>     5Xtqo&gTLA(_S)TQj!Kq"UP8<!<rr:&$QcW!"K,K&kWe?(^pl]#mUY<!s\f7"U>G:!%\s-3WRec
>     $pP.r$uZOWNsl$t"H>'?EW%CM&Cer:&f3P>eEnad5<Qq=rQYuk3AE2g>q7E*
>     EndTtf

これは ASCII85Encode で符号化された 107 バイトのバイナリデータです。

文字がアンカーポイントを含んでいれば、それらは以下のように取り込まれます:

>     AnchorPoint: "bottom" 780 -60 basechar 0
>     AnchorPoint: "top" 803 1487 basechar 0

アンカークラスが所属する点の名前 (UTF-7 で)、位置、点のタイプが (基底文字、マーク、基底合字、基底マーク、始筆、収筆のうち) どれであるか、そして合字については、それがどの合字要素を参照しているかを示す番号です。デバイステーブルをサポートする設定でコンパイルされた FontForge を使用している場合、以下のような記述が含まれているかもしれません:

>     AnchorPoint: "bottom" 780 -60 basechar 0 {12-13 -1,-1} {8-14 1,0,-1,-1,-2,-2,-2}

ここで、波括弧内の項目は水平/垂直デバイステーブルです。最初の括弧は、(水平) デバイステーブルが 12〜13 ピクセルの範囲のサイズで、それぞれ -1 ピクセルの補正を施すことを表しています。2 番目は、垂直デバイステーブルが 8〜14 ピクセルの範囲においてでそれぞれ 1, 0, -1, -1, -2, -2, -2 ピクセルの補正を施すことを表します。

最後に、TrueType フォントは 1 個のアンカーポイントをグリフ内の 1 個の基準点に基づいて配置することができます (これが行われる場合、デバイステーブルを置くことはできません)。

>     AnchorPoint: "bottom" 780 -60 basechar 0 23

は、このアンカーポイントが TrueType グリフの点番号 23 と同じ位置 (通常は (780,-60) ですが、命令によって移動することができます) に配置されることを表しています。

ユーザがグリフクラスを設定している場合、

>     GlyphClass: 2

この番号は、それが表す‘GDEF’グリフクラスよりも 1 つ大きい値になっています (ですから、この例の 2 はベースグリフ (クラス 1) を意味します)

その文字がカーニングペアのどれか (ただし、カーニングクラスに定義されているペアを除く) の先頭文字である場合:

>     KernsSLIFO: 60 -100 1 0 {12-13 -1,-1} 63 -92 1 0 70 -123 1 0 45 -107 1 0 76 -107 1 0

ここでは各カーニングペアは 4 個の数値 (および省略可能なデバイステーブル。上記参照) で表されます。最初に来るのは 2 番目の文字の (現在のフォント内での) 位置で、次に来るのは横書きのカーニング量で、スクリプト・言語インデックスがその次に置かれ、最後に OpenType のフラグが来ます。それから、次のカーニングペアの記述が始まります。

古い SFD ファイルは以下の僅かに異なるフォーマットの行を含んでいるかもしれません:

>     KernsSLIF: 114 -100 1 0 {12-13 -1,-1} 117 -92 1 0 101 -123 1 0 97 -107 1 0 111 -107 1 0

ここで、最初の数値はカーニングペアの 2 番目のグリフの符号位置です。

その他の GPOS, GSUB または GDEF サブテーブルに送られるデータは、以下のような形で格納されます:

>     Position: 12 0 'sinf' dx=0 dy=-900 dh=0 dv=0
>     PairPos: 12 0 'dist' B dx=0 dy=0 dh=0 dv=0  dx=-10 dy=0 dh=0 dv=0
>     Ligature: 12 0 'frac' one slash four
>     Substitution: 12 3 'smcp' agrave.sc
>     AlternateSubs: 12 0 'swsh' glyph490 A.swash
>     MultipleSubs: 12 0 'ccmp' a grave
>     Ligature: 12 4 'liga' f f
>     LCarets: 0 0 '    ' 1 650

これらの行のほとんどは、最初の 2 個の数値では用字系/言語インデックスと、一連の OpenType フラグの情報を提供しています (LCaret は例外で、それらは無視されます)。その後ろに OpenType が来ます (合字キャレットではこれらも無視されます)。単純位置変更はグリフの移動量とグリフの送り幅によって表現されます。ペア単位の位置指定は 2 個の隣り合うグリフの位置を指定します (カーニングはこの特殊な場合です)。合字には、それを構成する各文字の名前が含まれます。単純置換には、それが置き換えられる文字の名前が含まれます。選択型置換には、ユーザが選ぶ文字のリストが含まれます。複数置換は現在のグリフが分解される文字群が含まれます。合字キャレットには、定義されるキャレットの個数と、それらのキャレットの位置のリストが含まれます。

グリフには、それに付随する任意のコメント (UTF-7 で出力されます) や、

>     Comment: Hi

または色をもたせることができます。

>     Colour: ff0000

#### 複数レイヤフォント (Type3) のためのアウトラインフォントの拡張

これらは、FontForge の複数レイヤ編集機能が有効な設定のときのみにサポートされます。

複数レイヤフォントは“Fore”で前面レイヤを 1 個定義するだけでなく、複数のレイヤをもつ (ことが可能な) もので、各レイヤには、そのレイヤの塗りつぶしや太線のような物を指定する Layer: 行が存在し、各レイヤにはスプラインセット、参照のリストや画像のリストが含まれます (これらの任意の物を省略することができます)。これらの構文は、上で説明した通常の場合と同じです。

>     LayerCount: 3
>     Layer: 1  1 1 1  #fffffffe 1  #fffffffe 1 40 round round [1 0 0 1] []
>     SplineSet
>     ...
>     EndSplineSet
>     Layer: 2  1 0 1  #00ff00 1  #0000ff 1 19 miter butt [0.5 0 0 1] [10 5]
>     SplineSet
>     ...
>     EndSplineSet

LayerCount: 行は、グリフ内のレイヤの個数を指定します (背景レイヤはレイヤ 0 なので、この個数は実際に指定されている個数より 1 多くなります——背景レイヤは通常フォントと同様の方法で格納されますが、個数の勘定には入ります)。この行は必須ではなく、省略された (または間違いの) 場合、FontForge は自分で個数を算定します。

Layer: 行にはあまりにも多量すぎる情報を含んでいます。最初は何番目のレイヤかを表す数字です。その次には 3 個のブール値があり、1 個目はスプラインセットを塗り潰すかどうかを表し、2 番目はスプラインセットをストロークとして描くかどうかを表し、3 番目は現在のところ全く無意味です。その次に、塗り潰し色の RGB 値が続き (特別な値 #fffffffe は、色が継承されることを意味します)、次に透明度 (特別な値 -1 は、継承を意味します)。次にストロークの色と透明度が続きます。それからストロークの太さ (この場合も -1 が継承されることを表します)、線の結びのタイプ (miter, round, bevel, inherited のいずれか), 線端のタイプ (butt, round, square, inherited のいずれか)、ペンに適用される変換行列が来て、最後に、破線を表す配列が来ます。

この Layer 行から次の Layer 行 (またはこの文字の終り) までに来るすべての SplineSet, Ref, Images はこのレイヤの一部であるとして扱われます。

### ビットマップフォント

アウトライン文字の記述がすべて終った後、項目 EndChars が 1 個あり、ビットマップフォントはすべてその後に出現します。

>     EndChars
>     BitmapFont: 12 285 10 2 1
>     BDFStartProperties: 2
>     COMMENT 0 "This is a bdf comment property"
>     FONT_DESCENT 18 2
>     BDFEndProperties
>     Resolution: 75
>     BDFChar: 32 3 0 0 0 0
>     z
>     BDFChar: 3 33 3 0 1 0 9
>     ^d(.M5X7S"!'gMa

BitmapFont: 行には以下の数値が含まれます: フォントのピクセルサイズ、フォント内の可能な文字の個数、フォントの高さおよび深さおよび諧調 (1 ピクセルあたりのビット数) です。

そこには省略可能な BDF の属性値を書き込むことができます。何らかの属性がある場合には、“BDFStartProperties:”の後に属性の個数を並べた行が置かれます。指定した個数だけの属性行を並べ、最後に“BDFEndProperties”という行がくる必要があります。各属性は以下のような形で指定します:
`<NAME> <TYPE> <VALUE>`
ここで <NAME> は属性名、<TYPE> は 0: 文字列・1: アトム、2: 整数、3: 符号なし整数を表します。さらに、それらの値が (BDF ヘッダの他のどこかから持ってきた値ではなく) 真の設定値を表す場合に <TYPE> の値は 16 との論理和を取った値を格納します。<VALUE> は引用符で囲った文字列か整数かのいずれかです。

フォントのデザイン解像度を指定する“Resolution:”行 (省略可能) を最後に置くことができます。

これに続き、ビットマップ文字のリストが続きます。BDFChar: 行には以下の数値が含まれます: 元の位置、(フォント内での) 符号位置、幅、x 座標の最小値、y 座標の最小値、x 座標の最大値および y 座標の最大値です。もし、ビットマップに縦書メトリックが存在する場合、縦方向の送り幅が追加されます。この後ろには、上記の例のようにエンコードされた 1 組のデータがさらに続き、このデータの (エンコード前の) サイズは (ymax-ymin-1)*((xmax-xmin+8)/8) バイトになります。ここにはカラーテーブルはありません (上位ビットが画像の最初に来て、1 になっているビットが黒く塗られ、0 のビットが透明になります)。

ビットマップフォントは次のようにして終了します:

>     EndBitmapFont
>     BitmapFont: 17 285 14 3 1
>     BDFChar: 0 17 0 0 0 0
>     z
>     ...
>     EndBitmapFont
>     EndSplineFont

### CID キー指定フォント

CID フォントはわずかに異なる形で保存されます。それは通常のフォントヘッダで始まりますが、そこにはトップレベルの CID フォント辞書に含まれる情報が格納されます。上で述べたように、これには CID 文字集合 (登録簿、順序づけ、補遺番号) を指定する特別なキーを含んでいるでしょう。そこには以下のような行も含まれるはずです:

>     CIDVersion: 2.0
>     BeginSubFonts: 5 8318

`CIDVersion` はその名の通りです。`BeginSubFonts` 行では、 5 個のサブフォントが存在し、そのうちの最大のものは 8318 文字ぶんのスロットが含まれることを示します (この場合も、そのうちのいくつかは定義できません)。これに続きサブフォントのリスト (通常のフォントと同じ形で出力されます) と、それらに含まれる文字が続きます。トップレベルフォントのみがビットマップ文字、アンカークラスなどを含むことができます。

### マルチプルマスターフォント

マルチプルマスターフォントは異なるスタイルのファイルヘッダから始まり、それに続いて一連のサブフォントの置かれます。マルチプルマスターフォントに 4 個のインスタンスがある場合は、5 個のサブフォントが存在します (各インスタンスにつき 1 個、混ぜ合わせたフォントにもう 1 個)。フォントヘッダは以下のような形です:

>     SplineFontDB: 1.0
>     MMCounts: 4 2 0 0
>     MMAxis: Weight Width
>     MMPositions: 0 0 1 0 0 1 1 1
>     MMWeights: 0.31502 0.13499 0.38499 0.16499
>     MMAxisMap: 0 2 0=>50 1=>1450
>     MMAxisMap: 1 2 0=>50 1=>1450
>     MMCDV:
>     {
>     1 index 1 2 index sub mul 3 1 roll
>     1 2 index sub 1 index mul 3 1 roll
>     1 index 1 index mul 3 1 roll
>     pop pop
>     0 1 1 3 {index add} for 1 exch sub 4 1 roll
>     }
>     EndMMSubroutine
>     MMNDV:
>     {
>     exch 50 sub 1400 div
>     exch 50 sub 1400 div
>     }
>     EndMMSubroutine
>     BeginMMFonts: 5 0

"MMCounts" 行 では、このフォントに含まれるインスタンスの個数 (4) と軸の本数 (2) に加え、これが Apple 変形可能フォントであるか (0) と、その場合、そのフォントに含まれる名前つきスタイルの個数 (0) を指定します。"MMAxis" 行は、軸の名前を指定します。MMPositions 行は (インスタンスの個数×軸の本数 個の要素からなる) 実数の配列で、各インスタンスの各軸に沿った座標を記述します。MMWeights 行は、補間を行ったときにデフォルトフォントとなるインスタンスフォントのウェイト (混ぜ合わせ) を記述します。AxisMap 行が各軸ごとに 1 個存在し、これは、デザイン空間から正規化された空間への対応づけを提供します。最初の行

>     MMAxisMap: 0 2 0=>50 1=>1450

では、軸 0 には 2 箇所の点の対応づけが存在することを表します。片方は正規化された位置 0 で、デザイン位置 50 に該当し、もう片方は正規化された位置 1 でデザイン位置 1450 に該当します。ここに格納された 2 個のサブルーチンが存在し、どちらも単純な PostScript です。最初は /NormalizeDesignVector ルーチンで、2 番目は /ConvertDesignVector ルーチンです。

最後に、実際のインスタンスフォントが来ます。

Apple の‘*var’テーブル群 (‘fvar’,‘gvar’,‘avar’および‘cvar’) の情報を含むフォントはわずかにフォーマットが異なります。

>     MMCounts: 8 2 1 10
>     MMAxis: Weight Width
>     MMPositions: 1 0 -1 0 0 1 0 -1 -1 -1 1 -1 1 1 -1 1
>     MMWeights: 0 0 0 0 0 0 0 0
>     MMAxisMap: 0 3 -1=>0.479996 0=>1 1=>3.2
>     MacName: 0 0 6 "Weight"
>     MacName: 0 1 15 "Type de graisse"
>     ...
>     MMAxisMap: 1 3 -1=>0.619995 0=>1 1=>1.3
>     MacName: 0 0 5 "Width"
>     MacName: 0 1 7 "Largeur"
>     ...
>     MMNamedInstance: 0  3.2 1
>     MacName: 0 0 5 "Black"
>     MacName: 0 1 9 "Tr\217s gras"
>     ...

Adobe のフォーマットでは、座標は区間 [0, 1] をとりますが、Apple のフォーマットでは範囲は [-1, 1] となります。Adobe では一般に、軸ごとに 2 個のインスタンスを(極値で) 指定しますが、Apple では 3 つ (極値と、0 におけるデフォルトの設定) を想定しています。ですから Adobe 方式の 2 軸のフォントでは通常 4 個のインスタンスとデフォルトの版を含むことになりますが、Apple 方式のフォントでは 8 個のインスタンスとデフォルトの版を含むことになります。MMWeights フィールドは、Apple では不適切です。各軸には 1 組の名前があり、各種の言語に翻訳されたその軸の名前を表します。最後に、Apple ではデザイン空間上のいくつかの点に名前をつけることができます。ここでは Weight=3.2, Width=1 の点には“Black”または“Trés gras”という名前がつけられています。

## 自動保存フォーマット

エラー回復ファイルは ~/.FontForge/autosave に保存され、それらはランダムに見える名前がついていて最後に .asfd で終ります。これは上記の .sfd ファイルと非常によく似ています。

ある asfd ファイルが次の行で始まるとしたら:

>     Base: /home/gww/myfonts/fontforge/Ambrosia.sfd

この場合、それはそのファイル (これは SFD ファイルでもフォントファイルでも構いません) に適用された変更のリストであると想定されます。最初の行が "`Base:`" でない場合、新しいフォントであると想定されます。次の行には通常と同様の文字符号が含まれます。その次の行が `BeginChars` 行です。この行の数値はファイル内の文字数ではなく、フォント内に現れることのできる最大の数値です。その後ろにフォント内の変更された全ての文字のリストが (上で説明したフォーマットで) 続きます。

ビットマップは保存されません。グリッドの変更は保存されません。

— 前 — 目次 — 次 —

1ASCII85Encode: 4 バイトのバイナリを‘!’から‘u’までの ASCII 文字 5 文字に変換する符号化方式の一つです。バイナリ 4 バイト (b1 b2 b3 b4) があるとして、それに対して次の条件を満たす (c1 c2 c3 c4 c5) を探すことを考えましょう:

>     b1 * 2563  +  b2 * 2562  +  b3 * 256  +  b4 =
>     	c1 * 854  +  c2 * 853  +  c3 * 852  +  c4 * 85  +  c5

最終的な出力は、ci のそれぞれの値に 33 (‘!’) を加えることによって得られます。4 つのバイトがすべて 0 の場合、‘!!!!!’を書き出さないで代わりに文字‘z’を使うことができます。

残念ながら、バイナリデータのストリームの長さは必ずしも 4 で割り切れるわけではありません。そこで、一連のデータの最後に n バイトが残っていたとしましょう。その場合、4-n 個のゼロバイトをデータストリームの末尾に付け加え、上記の変換を適用し (すべてゼロの場合に‘z’を出力する特別な処理を除く)、ci のバイト列のうち最初の n+1 個を出力します。

ですから、1 個のバイト値 0 を変換するした場合には以下のようになります:

- 3 個の追加の 0 を後ろに追加する (n==1 ⇒ 4-1=3 バイトを追加)
- すべての ci が 0 になる
- それぞれに‘!’を加える (全バイトが‘!’になる)
- 2 個の‘!’を追加する (n+1 = 2 だから)