フォント:値型、埋め込み、フォールバック
NextPDF のフォントは、イミュータブルな FontInfo 値オブジェクトと、エンジンでの埋め込み方法を決める技術の型で構成されます。エンジンが使用するフォントはすべて埋め込まれます。レガシーな Base 14 参照は、同梱のメトリック互換代替フォントへフォールバックします。
インストール
「インストール」という見出しのセクションcomposer require nextpdf/core:^3概念の概要
「概念の概要」という見出しのセクションFontInfo は、エンジンがフォントを埋め込むために必要な情報をすべて保持する、単一のイミュータブルな値オブジェクトです。具体的には、ファミリーとスタイル、PostScript 名、デスクリプターフラグ、1000 単位の em にスケーリングされたメトリック、文字幅、グリフから Unicode へのマップ、フォワード cmap(Unicode からグリフ識別子)、生のフォントバイト列、さらに存在する場合は variation 軸、名前付きインスタンス、異体字セレクター、カーニングペア、縦書きメトリックを保持します。これは final readonly です。コンストラクターのシグネチャと public プロパティは固定されているため、パース済みフォントは安定して共有できる事実情報になります。実際に処理を行うメソッドは FontInfo::encodeText() だけです。これはエンコーディングリゾルバーを経由し、EncodedGlyphRun を返します。
FontType は、エンジンが埋め込む技術を列挙します。TrueType(シングルバイトエンコーディング)、TrueTypeUnicode(Unicode を多用するスクリプト向けのマルチバイト CID エンコーディング)、OpenType(Compact Font Format アウトライン)、Type1(PFB と AFM のペアから登録される PostScript Type 1)、および CidFont0(PostScript ベースの CID フォント)です。パーサーが割り当てる型によって、ライターが出力するフォント辞書の形式が決まります。
エンジンはフォントプログラムを埋め込むため、ドキュメントはインストール済みのシステムフォントに依存せず、どのビューアーでも同じようにレンダリングされます — ISO 32000-2 §9。TrueType プログラムは FontFile2 フォントデスクリプターのエントリーを通じて埋め込まれ、glyf、head、hhea、hmtx、loca、maxp の各テーブルを含める必要があります — ISO 32000-2 §9.6.5(RAG ダイジェストはライセンス上限により切り詰められています。_downgraded-claims-o3.md に記録されています)。Compact Font Format アウトラインテーブルを持つ OpenType プログラムは FontFile3 を通じて埋め込まれます — ISO 32000-2 §9.6.5(RAG ダイジェストは切り詰められています。同じログを参照してください)。サブセッターはこの必須テーブルセットをそのまま再構築するため、埋め込まれたサブセットは準拠したプログラムのまま維持されます。
フォールバックは、レガシーな Base 14 のケースを処理します。Base14SubstituteFonts は、正規化された Base 14 キー — helvetica、helveticab、times、courier など — を、同梱の Liberation Fonts ファイルにマッピングします。Liberation Sans、Serif、Mono は、それぞれ Helvetica または Arial、Times Roman、Courier とメトリック互換です。いずれも埋め込み TrueType フェイスであるため、標準 14 フォントの参照が要求する WinAnsiEncoding(Windows-1252)のラテン文字レパートリー全体、すなわちアクセント付きラテン文字、ユーロ記号、一般的な約物をレンダリングします(ISO 32000-2 Annex D.2)。Symbol と ZapfDingbats には寛容なライセンスのメトリック互換代替が存在しないため、意図的に置き換えられません。これらを必要とするドキュメントでは、埋め込み可能なフォントを登録する必要があります。リゾルバーは副作用を持ちません — キーがどのファイルにマッピングされるかを返すだけで、それ以上は行いません。レジストリへの登録は呼び出し側の責任であり、これによりロックのセマンティクスとウォームアップのパイプラインが維持されます。
API サーフェス
「API サーフェス」という見出しのセクション| 型 | 種別 | 主要メンバー | 安定性 | 導入バージョン |
|---|---|---|---|---|
FontInfo | final readonly クラス | $family, $style, $type, $unitsPerEm, $widths, $unicodeMap, $cmapForward, $fileData, $variationAxes, $kernPairs, getKey(), encodeText() | stable | 1.0.0 |
FontType | enum (string) | TrueType, TrueTypeUnicode, OpenType, Type1, CidFont0 | stable | 1.0.0 |
Base14SubstituteFonts | final クラス (internal) | 正規化された Base 14 キーから同梱された Liberation ファイルのパスへ | stable | 2.7.0 |
ShaperFactory | final クラス | default(), create(), wouldUseRealShaper() | stable | 3.2.0 |
ShapingResult | final readonly クラス | $glyphRuns, $originalText, $script, $direction, $shaperImpl | stable | 3.2.0 |
Base14SubstituteFonts は @internal です — フレームワーク内部でのみ使用する想定で、そのサーフェスには後方互換性の保証はありません。
コードサンプル — クイックスタート
「コードサンプル — クイックスタート」という見出しのセクション<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Typography\FontRegistry;use NextPDF\Typography\FontType;
$registry = new FontRegistry();$font = $registry->register('/path/to/NotoSansTC-Regular.ttf', alias: 'NotoSansTC');
// FontInfo is the immutable parsed fact about the face.echo $font->family, ' / ', $font->type->value, "\n"; // e.g. "Noto Sans TC / TrueTypeUnicode"assert($font->type === FontType::TrueTypeUnicode);パーサーは FontInfo を組み立て、FontType を割り当てます。Unicode cmap を持つ TrueType フェイスは TrueTypeUnicode となり、ライターはこれを Type 0 複合フォントとして出力します。
コードサンプル — 本番
「コードサンプル — 本番」という見出しのセクション<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Typography\Base14SubstituteFonts;use NextPDF\Typography\FontRegistry;
final readonly class Base14EmbeddingResolver{ public function __construct(private FontRegistry $registry) {}
/** * Register an embeddable substitute for a legacy Base 14 key so the * output document embeds every font (PDF/A-4 and PDF/UA-2 require it). */ public function ensureEmbeddable(string $base14Key): void { $path = Base14SubstituteFonts::resolve($base14Key);
if ($path === null) { // Symbol / ZapfDingbats have no permissive substitute — the // caller must supply its own embeddable font. throw new \RuntimeException("No bundled substitute for {$base14Key}"); }
if (!$this->registry->has($base14Key)) { $this->registry->register($path, alias: $base14Key); } }}リゾルバーは副作用を持ちません。登録は明示的なままなので、レジストリのロックとウォームアップの契約が維持されます。Symbol と ZapfDingbats は設計上、パスを返しません。
エッジケースと注意点
「エッジケースと注意点」という見出しのセクションSymbolとZapfDingbatsは意図的に置き換えられません。これらのキーに対する null の結果は、文書化された動作であり、フォント未検出のバグではありません。FontInfoはfinal readonlyです。パース済みフォントは値として扱ってください。幅やメトリックをその場で変更できるとは想定しないでください。ソースが変更された場合は、登録し直してください。- Type 1 フォントには、PFB アウトラインと AFM メトリックの両方が必要です。
FontRegistry::registerType1()はこのペアを受け取ります。自動検出では、PFB パスの拡張子から AFM パスを導出します。 FontType::TrueTypeとFontType::TrueTypeUnicodeの違いは、シングルバイトかマルチバイトかの区別です。エンコーディングリゾルバーは、ファミリー名ではなく、設定されたフォワード cmap を判定基準とするため、Unicode TrueType フェイスは自動的に Identity-H 経路へ振り分けられます。- バリエーションフォントの軸と名前付きインスタンスは、存在する場合は
FontInfoにパースされますが、ここで取り上げた CJK の例では、パース済みのFontInfoを決定論的に保つため、意図的に静的フェイスを使用しています。
パフォーマンス
「パフォーマンス」という見出しのセクションFontInfo は、レジストリによってプロセスごと・フォントごとに一度だけ割り当てられ、その後は参照で共有されます。生のフォントバイト列を保持するため、それがメモリーコストの大半を占めます。ワーカーは必要なフォントのみをウォームアップし、memoryUsage() を監視するようにしてください。Base 14 の代替リゾルバーは定数時間のマップ参照であり、呼び出し側が解決済みのファイルを登録するまで I/O は発生しません。実時間 1500 ms、ピーク 64 MB という performance_budget は、典型的なフォントセットのウォームアップとレンダリングをカバーします。フォントごとのメモリーフットプリントは、サブセッターが実行されるまでは、グリフ数ではなくフォントファイルのサイズに比例します。
セキュリティに関する注意
「セキュリティに関する注意」という見出しのセクションFontInfo 自体は不活性です — 純粋な encodeText() 変換以外の動作を持たない、パース済みデータです。攻撃対象領域は上流のパース時にあります。つまり、任意のフォントバイト列が TrueType または Type 1 パーサーに到達する箇所です。パーサーはすべてのバイナリオフセットに対して境界チェックを行い、パス内のストリームラッパーと null バイトを拒否します。信頼できないフォント入力は、登録前にサイズとグリフ数を制限する外部リソースポリシーを通過する必要があります。同梱の Liberation 代替フォントは、パッケージ内の信頼できるアセットであるため、フォールバック経路が新たな信頼できない入力をもたらすことはありません。
| 主張 | 規格 | 条項 | エビデンス |
|---|---|---|---|
| ドキュメントが使用するフォントはすべて埋め込まれるため、システムフォントに依存せずにレンダリングされます。 | ISO 32000-2 | §9 | |
TrueType プログラムは FontFile2 を通じて、glyf、head、hhea、hmtx、loca、maxp の各テーブルとともに埋め込まれます。 | ISO 32000-2 | §9.6.5 | RAG ダイジェストはライセンス上限により切り詰められています。プレフィックスは 7b26f37996239b2a、参照先は _downgraded-claims-o3.md |
OpenType (CFF) プログラムは FontFile3 を通じて埋め込まれます。 | ISO 32000-2 | §9.6.5 | RAG ダイジェストはライセンス上限により切り詰められています。プレフィックスは 801549ee00623baf、参照先は _downgraded-claims-o3.md |
最初の条項はダイジェストで固定されており、B1 によって裏付けられています。FontFile2 と FontFile3 の条項は言い換えられています。これらの完全な RAG ダイジェストは返されていません(ライセンス上限による切り詰め)。代わりに、FontSubsetter(これは glyf/head/hhea/hmtx/loca/maxp セットをそのまま再構築します)と FontType enum によって裏付けられています。NextPDF は規範テキストを複製しません。Base14SubstituteFonts はソース内で、ISO 32000-2 §9.6.2.2(標準 Type 1 フォントの取り扱い)、ISO 14289-2:2024 §8.4.5.5.1(PDF/UA-2 フォント埋め込み)、および ISO 19005-4:2020 §6.3.5(PDF/A-4 フォント埋め込み)を引用しています。完全なプロファイル準拠は、アクセシビリティと準拠のページに記載されています。
商用コンテキスト
「商用コンテキスト」という見出しのセクション商用のフォントライセンスパックと動的サブセット化サービスは、Core の FontInfo とレジストリの上に構築されています。Core のフォントモジュールは、ライセンスなしで埋め込み、サブセット化、フォールバックを行います。コンバージョンリンクが省略されているのは意図的です。
- タイポグラフィ: レジストリ、サブセット化、CMap、エンコーディング、BiDi —
FontInfoを生成・消費するレジストリとサブセット化について。 - テキスト: シェイピング、改行、BiDi — エンコード済みランを消費するシェイピング連携について。
- コントラクト / タイポグラフィ —
FontRegistryInterfaceのコントラクトについて。