Type 0 フォント (CID フォント)

Type 0 フォント
Type 0 フォントは、複数のフォントを子孫に持つフォントです。
PDF の場合は、CID フォント (CIDFontType0CIDFontType2 のサブタイプのフォント) を子孫に持ちます。

Type 0 フォントでは、OpenType や TrueType フォントを使用することができます。

CMap によって、文字コードと CID キーをマッピングするため、日本語など、多数のグリフが含まれるフォントで使われます。

※ PDF 1.6 からは、OpenType フォントをまるごと埋め込んで使用することができます。
※ CMap は別途、PostScript で記述して定義する必要があります。

サブセット(必要なグリフだけ抜き出したもの)で埋め込む場合は、フォント内の必要なグリフとテーブルの情報を抜き出した上で、フォントファイルを再構築する必要があるため、フォントフォーマットの知識が必要になります。

こちらのサイトでは、OpenType/TrueType のフォーマット仕様も解説していますので、フォントフォーマットについては、そちらを参考にしてください。
CID について
CID は「Character IDentifier」の略で、グリフの各文字に割り振られた、10進数の識別番号のことです。

CID は、Adobe によって、各言語ごとに文字コレクションとして規定されており、
2019年時点での日本語の最新版は Adobe-Japan1-7 となっています。

この最新版では、2万3060グリフが定義されています。
Type 0 フォント辞書
まずは、ルートとなる Type 0 のフォント辞書を定義する必要があります。
(単一のフォントであっても、必ず2つのフォント辞書の定義が必要になります)

Typename(必須) オブジェクトのタイプ。常に /Font
Subtypename(必須) フォントのサブタイプ。
Type 0 フォントの場合は、/Type0
BaseFontname(必須) フォントの PostScript 名。

子孫が CIDFontType0 (OpenType/CFF) の場合は、「CIDFont 辞書の BaseFont 名」+ '-' + 「この辞書の Encoding エントリの名前、または CMap の CMapName エントリの名前」を指定します。

子孫が CIDFontType2 (TrueType) の場合、CIDFont 辞書の BaseFont 名のみを指定します。
Encodingname or stream(必須) 定義済みの CMap 名、または、文字コードを CID にマッピングする CMap ストリーム。

子孫が、埋め込みではない CIDFontType2 の場合、定義済みの CMap 名を指定します。
DescendantFontsarray(必須) 子孫の CIDFont 辞書を指定する、一つの要素の配列。
※指定できるのは一つだけですが、必ず配列で指定します。
ToUnicodestream文字コードを Unicode 値にマッピングする CMap ストリーム

14 0 obj
<< /Type /Font
  /Subtype /Type0
  /BaseFont /HeiseiMin−W5−90ms−RKSJ−H
  /Encoding /90ms−RKSJ−H
  /DescendantFonts [ 15 0 R ]
>>
endobj
CIDFont 辞書
このフォント辞書では、Type 0 の子孫となるフォントを定義します。

Type 0 フォントの DescendantFonts エントリで、この辞書を指定します。

「Type 1 フォント (Type 0)」と「TrueType フォント (Type 2)」の2つのタイプが存在します。
OpenType または CFF 形式であれば前者、TrueType であれば後者を使います。

Typename(必須) オブジェクトのタイプ。常に /Font
Subtypename(必須) フォントのサブタイプ。
/CIDFontType0 または /CIDFontType2
BaseFontname(必須) PostScript 名。

CIDFontType0 の場合、CFF 内で定義されている PostScript 名。
CIDFontType2 の場合、前回説明した TrueType フォントの場合と同じ形式で指定します。

サブセットの場合、先頭にサブセットタグを付けることができます。
CIDSystemInfodictionary(必須) 文字コレクションを定義するエントリを含む辞書
FontDescriptordictionary(必須。間接参照) フォントの詳細情報を記述する辞書。
前回説明したものと同じですが、CIDFont のみで指定できるエントリがあります。
DWintegerグリフのデフォルトの幅。
default = 1000
Warray各グリフの幅を、可変フォーマットの配列で指定します。
default = なし (すべてのグリフで DW エントリの値を使う)。

2通りの記述形式があります。
配列内で、以下のいずれか、または両方の形式を使って記述します。

CID開始値 [幅1 幅2...] : CID 開始位置から順に、各グリフの幅を指定
CID先頭 CID終端 幅 : 指定した CID の範囲をすべて指定幅に
DW2array縦書き時のグリフのデフォルト情報を指定する、2つの数値の配列。

1つ目の数値は、横書きの原点から縦書きの Y 原点までの高さ (通常は Ascent と同じ)。
2つ目の数値は、次の文字へ移動する時の方向と縦幅。
(縦書きの X 原点は、固定グリフ幅の半分の位置となります)

default = [880 -1000] (CFF 形式の場合、この値であることが多い)
W2array縦書き時の各グリフの情報を定義する配列。
default = なし (全てのグリフで DW2 エントリの値を使う)

W エントリと同じような形で、以下の2通りで記述します。

CID開始値 [移動幅 原点水平位置 原点垂直位置]
CID先頭 CID終端 移動幅 原点水平位置 原点垂直位置
CIDToGIDMapstream or name(埋め込み CIDFontType2 のみ) CID からグリフインデックスへのマッピング。

ストリームの場合は、バイナリデータの配列。
(CID に対応する GID の値を並べる。各 2 byte でビッグエンディアン順にセット)

名前の場合は、マッピング ID。
/Identity の場合、CID とグリフインデックスは同じになる。

default = /Identity
CIDSystemInfo 辞書
CIDFont 辞書の CIDSystemInfo エントリで指定する辞書です。
文字コレクションの情報を定義します。

RegistryASCII string(必須) 文字コレクションの発行者 (Adobe など)
OrderingASCII string(必須) 文字コレクションの名前 (Japan1 など)
Supplementinteger(必須) 文字コレクションのサプリメント番号。

元の文字コレクションのサプリメント番号は 0 です。
文字コレクションで追加の CID が割り当てられるたびに、番号が増加します。

Adobe-Japan1-7 なら、それぞれ、「(Adobe)」「(Japan1)」「7」となります。

Adobe の文字コレクションに準拠しない場合は、Adobe-Identity-0 として指定します。

/CIDSystemInfo <<
  /Registry (Adobe)
  /Ordering (Japan1)
  /Supplement 5
>>
サブセット
サブセットフォント」とは、フォントから必要なグリフだけを抜き出して構築したフォントです。

日本語フォントなどの場合は、一つのフォント内に多くのグリフが含まれるため、フォントをまるごと埋め込むと、PDF ファイルのサイズが大きくなってしまいます。

実際に PDF 内で使われるグリフは、その中のほんの一部であることが多いため、必要なグリフだけ含めれば、ファイルサイズを減らすことができます。

フォントの埋め込みが許可されているか、また、サブセットの埋め込みが許可されているかは、フォントによって異なるため、PDF 作成時は、埋め込み可能なフォントであるかを確認してください。
なお、OpenType/TrueType フォントの場合は、OS/2 テーブル内に、フォント埋め込みに関するフラグが設定されています。

サブセットフォントを埋め込む場合、元のフォントの PostScript 名の前に、任意の6つの大文字からなる「サブセットタグ」を付けることが出来ます。

これにより、PDF 内の同じフォントの複数のサブセットを区別させることができます。

PostScript 名が "Test" だった場合は、その前に、6文字の大文字のタグ名と、'+' を付けます。
例: EOODIA+Test
CMap
Type 0 フォントでは、文字コードと CID をマッピングする情報 (CMap) が必要になります。

Type 0 フォント辞書の Encoding エントリで、CMap を指定します。
エントリの値には、「定義済みの CMap 名」か「CMap ストリーム」を指定します。

定義済みの CMap は、PDF を処理する側であらかじめ用意されているもので、各文字エンコーディングでの CID とのマッピング情報が定義されています。

定義済みの CMap に登録されていない文字を使いたい場合など、任意のマッピングを行いたい場合は、ストリームで CMap を記述して、指定します。

また、CMap には、横書き用と縦書き用があります。

例えば、「。」の場合は、横書き時と縦書き時でグリフが異なるため、別の CID が使われることになります。
そのため、横書きと縦書きで別のマッピングを行う必要があるため、CMap も横書き用と縦書き用に分けられます。

※ストリームで記述する CMap については、後で解説します。
定義済みの CMap
定義済みの CMap には、「中国語 (簡体字)、中国語 (繁体字)、日本語、韓国語、汎用」の5つの種類があります。
ここでは、日本語と汎用の CMap 名のみ列挙します。

※最後の H,V は、横書き用と縦書き用という意味です。

日本語
83pv-RKSJ-HMac OS、KanjiTalk6 拡張機能を備えた JIS X 0208 文字セット、
Shift-JIS エンコード、スクリプトマネージャーコード1
90ms−RKSJ−HMicrosoft コードページ 932(lfCharSet 0x80)、
NEC および IBM 拡張付き JIS X 0208 文字セット
90ms-RKSJ-V90ms-RKSJ-H の垂直バージョン
90msp-RKSJ-H90ms-RKSJ-H と同じですが、半角ラテン文字をプロポーショナルに置き換えます
90msp-RKSJ-V90msp-RKSJ-H の垂直バージョン
90pv-RKSJ-HMac OS、KanjiTalk7 拡張付き JIS X 0208 文字セット、
Shift-JIS エンコード、スクリプトマネージャーコード1
Add-RKSJ-HFujitsu FMR 拡張機能を備えた JIS X 0208 文字セット、Shift-JIS エンコーディング
Add-RKSJ-VAdd-RKSJ-H の垂直バージョン
EUC−HJIS X 0208 文字セット、EUC-JP エンコーディング
EUC−VEUC-H の垂直バージョン
Ext-RKSJ-HNEC 拡張付き JIS C 6226(JIS78)文字セット、Shift-JIS エンコード
Ext-RKSJ-VExt-RKSJ-H の垂直バージョン
HJIS X 0208 文字セット、ISO-2022-JP エンコーディング
VH の垂直バージョン
UniJIS−UCS2−HAdobe-Japan1 文字コレクション用の Unicode(UCS-2)エンコード
UniJIS−UCS2−VUniJIS-UCS2-H の垂直バージョン
UniJIS-UCS2-HW-HUniJIS-UCS2-H と同じですが、プロポーショナルラテン文字を半角に置き換えます
UniJIS-UCS2-HW-VUniJIS-UCS2-HW-H の垂直バージョン
UniJIS−UTF16-HAdobe-Japan1 文字コレクションの Unicode(UTF-16BE)エンコード。
JIS X 0213:1000 文字セットのすべての文字のマッピングが含まれます。
UniJIS−UTF16-VUniJIS-UTF16-H の垂直バージョン
汎用
Identity-H2バイト CID の横書き用 ID マッピング
Identity-VIdentity-H の垂直バージョン
各 PDF バージョンごとの文字コレクションの対応
CMapPDF 1.2PDF 1.3PDF 1.4PDF 1.5
83pv−RKSJ−HAdobe-Japan1-1Adobe-Japan1-1Adobe-Japan1-1Adobe-Japan1-1
90ms−RKSJ−H/VAdobe-Japan1-2Adobe-Japan1-2Adobe-Japan1-2Adobe-Japan1-2
90msp−RKSJ−H/V-Adobe-Japan1-2Adobe-Japan1-2Adobe-Japan1-2
90pv−RKSJ−HAdobe-Japan1-1Adobe-Japan1-1Adobe-Japan1-1Adobe-Japan1-1
Add−RKSJ−H/VAdobe-Japan1-1Adobe-Japan1-1Adobe-Japan1-1Adobe-Japan1-1
EUC−H/V-Adobe-Japan1-1Adobe-Japan1-1Adobe-Japan1-1
Ext−RKSJ−H/VAdobe-Japan1-2Adobe-Japan1-2Adobe-Japan1-2Adobe-Japan1-2
H/VAdobe-Japan1-1Adobe-Japan1-1Adobe-Japan1-1Adobe-Japan1-1
UniJIS−UCS2−H/V-Adobe-Japan1-2Adobe-Japan1-4Adobe-Japan1-4
UniJIS−UCS2−HW−H/V-Adobe-Japan1-2Adobe-Japan1-4Adobe-Japan1-4
UniJIS−UTF16−H/V---Adobe-Japan1-5
Identity−H/VAdobe-Identity-0Adobe-Identity-0Adobe-Identity-0Adobe-Identity-0

PDF のバージョンによって、各 CMap が対応している文字コレクションが異なります。

定義済みの CMap を使う場合、CIDFont 辞書の CIDSystemInfo エントリでは、各 CMap に応じた文字コレクションを指定する必要があります。
テキストの文字エンコーディング
Type 0 フォントを使って、グラフィック命令で文字列を描画する時、Tj 命令などのオペランドとして指定する文字列は、
"Type 0 フォント辞書の Encoding で指定されたエンコーディング" で記述する必要があります。

定義済みの CMap を指定した場合は、各 CMap ごとに指定された文字エンコーディングで、バイト文字列を記述します。
(UTF-16 など、2 byte 単位の場合は、ビッグエンディアン順で記述)
エンコーディングの指定がある CMap の場合
例えば、UniJIS−UTF16−H の場合は、Unicode の UTF-16 エンコーディングであるため、以下のように記述します。

% あ(U+3042) + い(U+3044)
<30423044> Tj

PDF 構文として、Unicode 文字列を記述する時は、先頭に BOM (FE,FF) を付けることになっていましたが、これは、目次などで Unicode 文字を表示したい時に使う構文です。
グラフィックでのテキスト指定時は、文字エンコーディングが直接指定されているので、Unicode 文字を使う場合において、BOM を付けるは必要ありません。

90ms−RKSJ−H の場合は、Shift-JIS エンコードであるため、同じく "あい" を表示する時は、以下のようになります。

% あ(82A0) + い(82A2)
<82A082A2> Tj

EUC−H であれば、EUC エンコードとなります。
Identity−H/V の場合
CMap が Identity−H または Identity−V の場合は、明示的なエンコーディングの指定はありません。
この場合、文字コードの値が、直接、CID またはグリフインデックスの値となります。

つまり、文字コードから CID への変換を行う過程が省かれます。

文字コードは1文字 = 2 byte とし、ビッグエンディアン順で記述します。

なお、この場合に問題となるのは、グリフの文字を Unicode などの文字列として取得できないことです。
このままでは、PDF 内のテキストのコピーや抽出が行えません。

これを解決するために、PDF では、CID/GID から Unicode へのマッピング情報を指定することができます。
これによって、各文字を Unicode に変換して、文字列として取得することができます。

マッピングは CMap ストリームで定義し、Type 0 フォント辞書の ToUnicode エントリで指定します。
使用例
ここでは、埋め込みではなく、OS にインストールされているフォントを使う場合の例です。
TrueType
% リソース辞書
4 0 obj
<< /Font << /FONT1 6 0 R >>
>>
endobj

% コンテンツストリーム
5 0 obj
<< /Length 42 >>
stream
/FONT1 24 Tf
BT
10 500 Td
<30423044> Tj
ET
endstream
endobj

% Type 0 フォント辞書
6 0 obj
<< /Type /Font
   /Subtype /Type0
   /BaseFont /IPAPGothic
   /Encoding /UniJIS-UTF16-H
   /DescendantFonts [7 0 R]
>>
endobj

% CIDFont 辞書
7 0 obj
<< /Type /Font
   /Subtype /CIDFontType2
   /BaseFont /IPAPGothic
   /CIDSystemInfo <<
     /Registry (Adobe)
     /Ordering (Japan1)
     /Supplement 5
   >>
   /FontDescriptor 8 0 R
>>
endobj

% FontDescriptor 辞書
8 0 obj
<< /Type /FontDescriptor
   /FontName /IPAPGothic
   ...
>>
endobj
OpenType
% Type 0 フォント辞書
6 0 obj
<< /Type /Font
   /Subtype /Type0
   % 'NotoSansMonoCJKjp-Regular' + '-' + 'Identity-H'
   /BaseFont /NotoSansMonoCJKjp-Regular-Identity-H
   /Encoding /Identity-H
   /DescendantFonts [7 0 R]
>>
endobj

% CIDFont 辞書
7 0 obj
<< /Type /Font
   /Subtype /CIDFontType0
   /BaseFont /NotoSansMonoCJKjp-Regular
   /CIDSystemInfo <<
     /Registry (Adobe)
     /Ordering (Identity)
     /Supplement 0
   >>
   /FontDescriptor 8 0 R
>>
endobj

8 0 obj
<< /Type /FontDescriptor
   /FontName /NotoSansMonoCJKjp-Regular
   ...
>>
endobj