Шрифт: типы значений, встраивание и резервная замена
В NextPDF шрифт описывается неизменяемым объектом-значением FontInfo и типом технологии: по нему движок понимает, как встроить шрифт. Движок встраивает каждый используемый шрифт. Устаревшая ссылка на Base 14 заменяется встроенным в пакет метрически совместимым аналогом.
Установка
Заголовок раздела «Установка»composer require nextpdf/core:^3Концептуальный обзор
Заголовок раздела «Концептуальный обзор»FontInfo — неизменяемый объект-значение, который содержит всё необходимое движку для встраивания шрифта: семейство и начертание, имя PostScript, флаги дескриптора, метрики, приведённые к em из 1000 единиц, ширины символов, отображение глифов в Unicode, прямое отображение символов (cmap, из Unicode в идентификатор глифа), необработанные байты шрифта, а также, при наличии, оси вариаций, именованные экземпляры, селекторы вариаций, пары кернинга и вертикальные метрики. Класс объявлен как final readonly. Сигнатура его конструктора и публичные свойства зафиксированы, поэтому разобранный шрифт становится стабильным фактом, пригодным для совместного использования. FontInfo::encodeText() — единственный метод с поведением. Он обращается к резолверу кодировки и возвращает EncodedGlyphRun.
FontType перечисляет шрифтовые технологии, которые встраивает движок: TrueType (однобайтовая кодировка), TrueTypeUnicode (многобайтовая кодировка по идентификатору символа (CID) для письменностей с большим набором Unicode-символов), OpenType (контуры в формате Compact Font Format), Type1 (PostScript Type 1, регистрируемый из пары Printer Font Binary (PFB) и Adobe Font Metrics (AFM)) и CidFont0 (CID-шрифт на основе PostScript). Назначенный парсером тип определяет структуру словаря шрифта, который выводит модуль записи.
Чтобы отрисовка не зависела от установленных системных шрифтов, движок встраивает программу шрифта — ISO 32000-2 §9. Программа TrueType встраивается через запись дескриптора шрифта FontFile2 и должна включать таблицы glyf, head, hhea, hmtx, loca и maxp — ISO 32000-2 §9.6.5. Программа OpenType с таблицей контуров в формате Compact Font Format встраивается через FontFile3 — ISO 32000-2 §9.6.5. Модуль создания подмножеств перестраивает именно этот обязательный набор таблиц, поэтому встроенное подмножество остаётся программой, соответствующей требованиям.
Резервная замена покрывает устаревший сценарий Base 14. Base14SubstituteFonts сопоставляет нормализованный ключ Base 14 — helvetica, helveticab, times, courier и остальные — с файлом Liberation Fonts из пакета. Liberation Sans, Serif и Mono метрически совместимы с Helvetica или Arial, Times Roman и Courier. Каждый из них — встроенное начертание TrueType, поэтому он отрисовывает полный латинский репертуар WinAnsiEncoding (Windows-1252), который требует эталон стандартных 14 шрифтов: латиницу с диакритикой, знак евро и распространённую типографскую пунктуацию (ISO 32000-2 Annex D.2). Для Symbol и ZapfDingbats нет метрически совместимой замены со свободной лицензией, поэтому NextPDF намеренно их не подставляет; документ, которому нужен любой из этих шрифтов, должен зарегистрировать встраиваемый шрифт. Резолвер не имеет побочных эффектов: он только сообщает, какому файлу соответствует ключ. Вызывающая сторона по-прежнему отвечает за регистрацию в реестре, сохраняя семантику блокировки и конвейер прогрева.
Поверхность API
Заголовок раздела «Поверхность API»| Тип | Разновидность | Ключевые члены | Стабильность | С версии |
|---|---|---|---|---|
FontInfo | final readonly class | $family, $style, $type, $unitsPerEm, $widths, $unicodeMap, $cmapForward, $fileData, $variationAxes, $kernPairs, getKey(), encodeText() | стабильно | 1.0.0 |
FontType | enum (string) | TrueType, TrueTypeUnicode, OpenType, Type1, CidFont0 | стабильно | 1.0.0 |
Base14SubstituteFonts | final class (внутренний) | нормализованный ключ Base 14 в путь к файлу Liberation из пакета | стабильно | 2.7.0 |
ShaperFactory | final class | default(), create(), wouldUseRealShaper() | стабильно | 3.2.0 |
ShapingResult | final readonly class | $glyphRuns, $originalText, $script, $direction, $shaperImpl | стабильно | 3.2.0 |
Base14SubstituteFonts помечен как @internal: только для внутреннего использования фреймворком, без гарантии обратной совместимости этой API-поверхности.
Пример кода — быстрый старт
Заголовок раздела «Пример кода — быстрый старт»<?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. Начертание TrueType с символьной картой Unicode становится типом 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()принимает эту пару; автоопределение выводит путь AFM из пути PFB по расширению. FontType::TrueTypeиFontType::TrueTypeUnicodeфиксируют различие между однобайтовым и многобайтовым вариантами. Резолвер кодировки использует заполненное прямое отображение символов, а не имя семейства, поэтому начертание Unicode TrueType автоматически направляется по пути Identity-H.- Оси вариаций шрифта и именованные экземпляры разбираются в
FontInfoпри их наличии, но подробный пример для китайского, японского и корейского языков (CJK) намеренно использует статическое начертание, чтобы разобранныйFontInfoоставался детерминированным.
Производительность
Заголовок раздела «Производительность»Реестр создаёт FontInfo один раз на шрифт в каждом процессе, а затем предоставляет его по ссылке. Основная часть памяти уходит на необработанные байты шрифта. Прогревайте только те шрифты, которые нужны воркеру, и отслеживайте memoryUsage(). Резолвер замены Base 14 выполняет поиск по карте за константное время без операций ввода-вывода (I/O), пока вызывающая сторона не зарегистрирует найденный файл. Параметр performance_budget в 1500 мс реального времени и 64 МБ пикового потребления покрывает прогрев типичного набора шрифтов и отрисовку. До запуска модуля создания подмножеств объём занимаемой памяти каждого шрифта зависит от размера файла шрифта, а не от количества глифов.
Замечания по безопасности
Заголовок раздела «Замечания по безопасности»FontInfo сам по себе инертен: это разобранные данные без какого-либо поведения, кроме чистого преобразования encodeText(). Поверхность атаки находится раньше в конвейере, на этапе разбора, когда произвольные байты шрифта попадают в парсер TrueType или Type 1. Парсеры проверяют границы каждого двоичного смещения и отклоняют обёртки потоков и нулевые байты в путях. Перед регистрацией недоверенные входные данные шрифта должны пройти проверку политики внешних ресурсов, которая ограничивает размер и количество глифов. Входящие в пакет заменители Liberation — это доверенные ресурсы, поставляемые вместе с пакетом, поэтому путь резервной замены не вносит новых недоверенных входных данных.
Соответствие требованиям
Заголовок раздела «Соответствие требованиям»| Утверждение | Стандарт | Пункт |
|---|---|---|
| Каждый шрифт, используемый документом, встроен, поэтому документ отображается без опоры на системные шрифты. | ISO 32000-2 | §9 |
Программа TrueType встраивается через FontFile2 с таблицами glyf, head, hhea, hmtx, loca, maxp. | ISO 32000-2 | §9.6.5 |
Программа OpenType (CFF) встраивается через FontFile3. | ISO 32000-2 | §9.6.5 |
Пункты о FontFile2 и FontFile3 являются перефразированиями; это поведение также отражено в FontSubsetter (который перестраивает именно набор glyf/head/hhea/hmtx/loca/maxp) и в перечислении FontType. 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). Полное соответствие профилям описано на страницах о доступности и соответствии требованиям.
Коммерческий контекст
Заголовок раздела «Коммерческий контекст»Коммерческий пакет лицензирования шрифтов и сервис динамического создания подмножеств построены на FontInfo из Core и реестре. Модуль шрифтов Core встраивает, создаёт подмножества и выполняет резервную замену без лицензии. Ссылка на конверсию намеренно отсутствует.
См. также
Заголовок раздела «См. также»- Типографика: реестр, создание подмножеств, CMap, кодировка, BiDi — процесс реестра и создания подмножеств, который порождает и потребляет
FontInfo. - Текст: формирование, перенос, BiDi — слой формирования, который потребляет закодированный поток глифов.
- Контракты / Типографика — контракт
FontRegistryInterface.