CFF テーブル (1)

CFF テーブルについて
CFF テーブル」には、PostScript アウトラインのデータが格納されています。
CFF フォントの内容が、そのまま丸ごと入っている形となります。

さらに、OpenType 1.8 では、「CFF2 テーブル」が追加されました。
基本的に CFF テーブルと同じ構造になりますが、いくつかの重複したデータが省略され、可変フォントに対応しています。

CFF フォーマットの仕様書は、下記にあります。
The Compact Font Format Specification (PDF)
CFF の構造
バイト順は「ビッグエンディアン」で、すべてのデータでバイト境界はありません。

先頭から順に、以下のデータが並んでいます。

Headerヘッダ
Name INDEXPostScript フォント名
Top DICT INDEX各フォントの主要情報
String INDEXフォントで使われるすべての文字列
Global Subr INDEXグローバルサブルーチン

その他のデータは、「Top DICT」などで指定されているオフセット値から、格納されている場所へアクセスできます。

それぞれのデータは、独自形式か、共通したフォーマットである「INDEX 構造」「DICT 構造」のデータで格納されています。

Name INDEX」は、INDEX のデータ構造で、フォント名が格納されていることになります。
データ型
Card8符号なし 8bit
Card16符号なし 16bit
Offsetオフセット値。1〜4 byte の可変サイズ。
OffSizeOffset のバイトサイズ (1〜4)。
符号なし 8bit。
SID文字列 ID (0〜64999)。
符号なし 16bit。
ヘッダ
先頭にあるデータです。

Card8 majorメジャーバージョン = 1
Card8 minorマイナーバージョン = 0
Card8 hdrSizeこのヘッダ全体のサイズ (CFF は 4)。
CFF 先頭から、Name INDEX へ移動するための値となります。

なお、CFF2 の場合は 5 で、下の値が u16 topDictLength となっています。
OffSize offSizeCFF の先頭を 0 とするオフセット値の、バイトサイズ。
実際には使われないので、無視して構いません。
INDEX 構造
データを配列で扱うための構造です。

Card16 countオブジェクトの数
OffSize offsize以下の Offset のバイトサイズ
Offset offset[count + 1]各データのオフセット値の配列。
data の先頭を 1 とした値なので、0 以外となる。
データのサイズは、offset[i + 1] - offset[i] で求める。
Card8 data[可変]オブジェクトデータの領域。
先頭から順にバイトの隙間なく並べる。

オフセット値は、data の先頭を 0 とすると、実際には offset - 1 で位置を取得することになるので、注意してください。

空の INDEX は、count が 0 で、以下のデータはなく、全体で 2 byte のデータとなります。

offset 配列の最後の値は、「data のサイズ + 1」となります。
DICT 構造
「キー」と「値」がペアとなる、辞書データです。

  • 「値 (複数可)」「キー」「値」「キー」... という順で、連続して並んでいます。
  • データのサイズ分、繰り返し読み込んでいきます。
  • 「キー」は 1〜2 byte。
    「値」は、整数または実数で、可変長データです。
    値は複数個連続して並ぶ場合があります。
  • 最初のバイト値で、キーか値かを判別できます。
    0〜21」はキー。
    28、29、30、32〜254」は値。
    22〜27、31、255」は予約されています。
キー
キーは、1バイト目が「12」の場合、2バイト目があります。
1バイト目が 12 以外なら、そのまま 1 byte 値となります。

例えば、「12, 1」という 2byte の値であれば、キーは「12 と 1」になります。
2つの値を合わせて、1つの値を作るといったことはしません。
値のタイプ
number整数値、または実数
boolean0 (false) or 1 (true)
SID文字列 ID
array配列
delta数値の差分の配列。
2番目以降の値は、一つ前との差の値が格納される。
(a0, a1 - a0, a2 - a1,...)
整数値
可変長 (1〜5 byte) によって、数値が表されます。
以下は、バイトが順に b0, b1, b2, b3, b4 と並んでいる場合の計算方法です。

b0 の値の範囲バイト数値の範囲値の計算方法
32 - 2461-107 〜 107b0 - 139
247 - 2502108 〜 1131(b0 - 247) * 256 + b1 + 108
251 - 2542-1131 〜 -108-(b0 - 251) * 256 - b1 - 108
28316bit 符号あり(int16)((b1 << 8) | b2)
29532bit 符号あり(int32)((b1 << 24) | (b2 << 16) | (b3 << 8) | b4)
実数
1バイト目が 30 の場合は、可変長の実数値となります。
2バイト目以降は、上位 4bit・下位 4bit にそれぞれ、以下の値が格納されています。

4bit値意味
0 - 90 〜 9
10 (0xA). (小数点)
11 (0xB)E
12 (0xC)E-
13 (0xD)予約
14 (0xE)- (マイナス)
15 (0xF)値の終了

値が -2.25 なら、「1E(30) E2('-2') A2('.2') 5F('5'END)」となります。
Name INDEX
ヘッダの直後に続くデータです。
すべてのフォントの、PostScript フォント名が格納されています。

INDEX 構造データで、オブジェクトデータは文字列となります。

CFF フォントは複数のフォントを格納できますが、OpenType フォント内の CFF では、1つのフォント名のみとなります。
String INDEX
「Name INDEX」の直後に続くデータです。

フォントで使われるすべての文字列が格納されています。
(フォントの名前や、グリフ名など)

INDEX 構造データで、オブジェクトデータは文字列となります。
データがない場合は、空の INDEX データとなります。

ここの文字列は、フォント内の「SID」の値によって参照されます。

SID 0 〜 390定義済みの標準文字列
SID 391〜String INDEX に格納された文字列。
配列内の、「SID - 391」の位置から文字列を取得することになります。
Top DICT INDEX
「String INDEX」の直後に続くデータです。

「Name INDEX」の各フォントに対応した、フォントの主要な情報が格納されています。
INDEX 構造データで、オブジェクトデータは DICT 構造です。

通常は1つのフォントの情報しかないので、INDEX の数は1つとなります。
値の一覧
オフセット値は、CFF の先頭を 0 とした値です。
デフォルト値は、項目が指定されていなかった場合に設定される値です。

名前キー値タイプデフォルト値、解説
version0SID-
Notice1SID-
Copyright12, 0SID-
FullName2SID-
FamilyName3SID-
Weight4SID-
isFixedPitch12, 1booleanfalse
ItalicAngle12, 2number0
UnderlinePosition12, 3number-100
UnderlineThickness12, 4number50
PaintType12, 5number0
CharstringType12, 6number2
FontMatrix12, 7array0.001, 0, 0, 0.001, 0, 0
UniqueID13number-
FontBBox5array0, 0, 0, 0
StrokeWidth12, 8number0
XUID14array-
charset15number0
charset データのオフセット値 (または charset ID)
Encoding16number0
Encoding データのオフセット値
CharStrings17number-
CharStrings INDEX のオフセット値
Private18number, number-
Private DICT のサイズとオフセット値
SyntheticBase12, 20number-
PostScript12, 21SID-
BaseFontName12, 22SID-
BaseFontBlend12, 23delta-
CID フォント
ROS12, 30SID, SID, number-
CIDFontVersion12, 31number0
CIDFontRevision12, 32number0
CIDFontType12, 33number0
CIDCount12, 34number8720
UIDBase12, 35number-
FDArray12, 36number0
Font DICT INDEX のオフセット値
FDSelect12, 37number0
FDSelect のオフセット値
FontName12, 38SID-
Font DICT で使われる。
Top DICT INDEX 以降のデータ
Top DICT INDEX 以降は、Top DICT で指定された各データのオフセット値を使って、データを読み込んでいきます。

Encoding※ OpenType での格納時、このデータは省略されているので、読み込みません。
charsetGID と SID/CID を関連付けるためのデータ。
CharStringsすべてのグリフのアウトラインデータ。
PrivateDICT 構造による、フォントの内部的な情報。
Charsets
「Top DICT」の「charset (key = 15)」のオフセット値を使って、読み込みます。
各 GID から、対応する SID または CID を取得するためのデータです。

CID フォントの場合は CID、CID フォントでない場合は、SID の値となります。

欧文など、グリフ数が少ないフォントでは、各グリフごとに SID でグリフ名が定義されています。
グリフ数の多い日本語などのフォントでは、グリフの名前ではなく、CID の番号を使います。

フォントによっては、グリフ ID と SID/CID が同一で一致する場合もありますが、そうでない場合もあるので、ここで、GID → SID/CID のマップを定義します。

データは Charsets の独自形式で、フォーマットは3つあります。
charset ID
Top DICT の charset 値が「0〜2」の場合は、定義済みの文字セットとなります。
Top DICT に charset が存在しない場合、デフォルト値は 0 となるため、「ISOAdobe」となります。

0ISOAdobe
1Expert
2ExpertSubset
フォーマット
GID = 0 (.notdef)」のデータは省略されているため、「GID 1〜」のデータとなります。

Format 0 (配列)
Card8 formatフォーマット番号 = 0
SID glyph[nGlyphs - 1]SID の配列

nGlyphs は、「CharStrings INDEX」の count 値。

Format 1 (範囲: Card8)
Card8 formatフォーマット番号 = 1
struct Range1[可変]データの配列

▼ Range1 構造体
SID first範囲の最初の SID
Card8 nLeft範囲の数 - 1

GID の 1 から順番に、「GID 〜 GID + nLeft」が、「first 〜 first + nLeft」に対応しています。
データの数は指定されていないので、グリフ数分が処理されるまで、続けます。

Format 2 (範囲: Card16)
Card8 formatフォーマット番号 = 2
struct Range2[可変]データの配列

▼ Range2 構造体
SID first範囲の最初の SID
Card16 nLeft範囲の数 - 1

Format 1 との違いは、nLeft の型。
CharStrings INDEX
Top DICT の「CharStrings (key = 17)」のオフセット値から読み込みます。
すべてのグリフのアウトラインデータが格納されています。

INDEX 構造データで、オブジェクトデータはバイナリ値です。
INDEX の count 値が、フォントに含まれるグリフ数となります。

配列は、グリフ ID によってアクセスされます (SID/CID ではない)。
最初のグリフは「GID = 0 (.notdef)」である必要があります。

データの形式は、Top DICT の「CharstringType」値で指定されます (OpenType では 2 で固定)。
以下に、Type2 CharString の仕様書があります。

The Type 2 Charstring Format

アウトラインデータのフォーマットについては、後で説明します。
CID フォント
CID フォント」は、主に CJK (中国語/日本語/韓国語) フォントにおいて、多数のグリフを扱うために設計された、PostScript フォントです。

基本的に CFF のフォーマットのままで扱いますが、格納されているデータが一部異なります。

  • 「Top DICT」には、一番最初に「ROS (key = 12,30)」のデータがある。
  • 「Top DICT」に、「FDArray」「FDSelect」の値が存在する。
    これは両方ともオフセット値である。
  • 「Charsets」のデータでは、値を CID として扱う。
    なお、CID フォントには、事前定義された文字セットは存在しない。
ROS
ROS は、「Registry Ordering Supplement」の略です。
それぞれ、「登録者」「配列」「追補番号」となっており、CID の文字コレクションを表します。

Top DICT では、この値は「<SID> <SID> <number>」という3つの数値から成り、
それぞれ、「Registry の文字列 ID」「Ordering の文字列 ID」「Supplement の数値」となっています。

Adobe-Japan1-6」なら、「"Adobe"」「"Japan1"」「6」となります。

源ノ明朝では「Adobe-Identity-0」となっていますが、これは、フォントごとに独自に定義された文字コレクションであることを表します。
FDArray と FDSelect
※ FD は、「Font DICT」の略です。

CID フォントはグリフ数が多いので、各グリフを、文字種などのいくつかのグループに分けて、それらをサブフォントとして扱います。

FDArray には、各サブフォントの情報の配列があり、FDSelect には、各 GID からサブフォントのインデックス値を取得するためのデータがあります。

まず、FDSelect で、GID に対応したサブフォントのインデックス値を取得し、FDArray (Font DICT INDEX) の配列から、インデックス位置を使って、DICT データを取得します。

DICT データには、「FontName (key = 12,38)」と「Private (key = 18)」のデータのみがあります。
サブフォントのフォント名と、Private DICT のオフセット値です。
FDSelect
Charsets と同じような独自形式となっています。
※ただし、ここでは「GID = 0 (.notdef)」も含まれます。

Format 0 (配列)
Card8 formatフォーマット番号 = 0
Card8 fds[nGlyphs]各グリフの FD インデックス値

nGlyphs は、CharStrings INDEX の count 値。

Format 3 (範囲)
Card8 formatフォーマット番号 = 3
Card16 nRanges配列の数
struct Range3[nRanges]範囲データ
Card16 sentinel最後の first 値 (最後の GID + 1)

▼ Range3 構造体
Card16 first範囲の最初の GID
Card8 fd範囲の全てのグリフに対応する FD インデックス値

同じ FD インデックスを持つ GID のグループが定義されています。

GID は、「first 〜 "次のデータの first" - 1」までの範囲となり、小さい値から順に連続して繋がっています。
一番最初の GID は、0 でなければなりません。

「sentinel」は、Range3 の配列の最後のデータから、次の first を得るための値です。
つまり、「最後の GID + 1」=「グリフ数」となります。
Private DICT の値
Top DICT または Font DICT の「Private (key = 18)」のオフセット値から読み込みます。
グリフに関する各情報が入っています。

名前キー値データ型デフォルト、説明
BlueValues6delta-
OtherBlues7delta-
FamilyBlues8delta-
FamilyOtherBlues9delta-
BlueScale12,9number0.039625
BlueShift12,10number7
BlueFuzz12,11number1
StdHW10number-
StdVW11number-
StemSnapH12,12delta-
StemSnapV12,13delta-
ForceBold12,14booleanfalse
LanguageGroup12,17number0
ExpansionFactor12,18number0.06
initialRandomSeed12,19number0
Subrs19numberローカルサブルーチンのオフセット値。
Private DICT データの先頭を 0 とした値。
defaultWidthX20number0
デフォルトのグリフ送り幅 (CharString で幅が指定されていない場合)
nominalWidthX21number0
CharString で幅が指定されていた場合の基本幅 (この値を足す)