Ga naar inhoud

Lettertypen: waardetypen, inbedding en fallback

In NextPDF wordt een lettertype vastgelegd als het onveranderlijke FontInfo-waardeobject, samen met het technologietype dat de engine vertelt hoe het moet worden ingebed. De engine bedt elk gebruikt lettertype in. Een verouderde Base 14-verwijzing valt terug op een meegeleverde, metriek-compatibele substitutie.

Terminal window
composer require nextpdf/core:^3

FontInfo is het onveranderlijke waardeobject dat de engine alles biedt wat nodig is om een lettertype in te bedden: familie en stijl, de PostScript-naam, descriptorvlaggen, metrieken geschaald naar een em van 1000 eenheden, tekenbreedtes, de glyph-naar-Unicode-toewijzing, de voorwaartse tekentoewijzing (cmap, Unicode naar glyph-identificatie), ruwe lettertype-bytes en, indien aanwezig, variatie-assen, benoemde instanties, variatieselectoren, kernparen en verticale metrieken. Het is final readonly. De constructorsignatuur en de publieke eigenschappen zijn bevroren, zodat een geparseerd lettertype een stabiel, deelbaar gegeven is. FontInfo::encodeText() is de enige methode met gedrag. Die loopt via de encoding-resolver en retourneert een EncodedGlyphRun.

FontType somt de technologieën op die de engine inbedt: TrueType (single-byte-codering), TrueTypeUnicode (multi-byte character-identifier-codering (CID) voor Unicode-rijke schriften), OpenType (Compact Font Format-omtrekken), Type1 (PostScript Type 1, geregistreerd vanuit een paar van Printer Font Binary (PFB) en Adobe Font Metrics (AFM)) en CidFont0 (een PostScript-gebaseerd CID-lettertype). Het door de parser toegewezen type bepaalt de vorm van de lettertype-dictionary die de writer wegschrijft.

Om de weergave onafhankelijk te houden van geïnstalleerde systeemlettertypen, bedt de engine het lettertypeprogramma in — ISO 32000-2 §9. Een TrueType-programma wordt ingebed via de FontFile2 font-descriptor-entry en moet de tabellen glyf, head, hhea, hmtx, loca en maxp bevatten — ISO 32000-2 §9.6.5 (RAG-digest afgekapt door de licentielimiet; vastgelegd in _downgraded-claims-o3.md). Een OpenType-programma met een Compact Font Format-omtrektabel wordt ingebed via FontFile3 — ISO 32000-2 §9.6.5 (RAG-digest afgekapt; zie hetzelfde logboek). De subsetter bouwt precies deze vereiste tabellenset opnieuw op, zodat de ingebedde subset een conform programma blijft.

De fallback dekt het verouderde Base 14-geval. Base14SubstituteFonts koppelt een genormaliseerde Base 14-sleutel — helvetica, helveticab, times, courier en de rest — aan een meegeleverd Liberation Fonts-bestand. Liberation Sans, Serif en Mono zijn metriek-compatibel met respectievelijk Helvetica of Arial, Times Roman en Courier. Elk daarvan is een ingebed TrueType-lettertype, dus het geeft het volledige Latijnse repertoire van WinAnsiEncoding (Windows-1252) weer dat een standaard-14-verwijzing vereist — Latijn met accenten, het euroteken en gangbare typografische interpunctie (ISO 32000-2 Annex D.2). Symbol en ZapfDingbats hebben geen toegestane metriek-compatibele vervanging, dus NextPDF substitueert ze bewust niet; een document dat een van beide lettertypen nodig heeft, moet een inbedbaar lettertype registreren. De resolver heeft geen neveneffecten: hij geeft alleen aan naar welk bestand een sleutel verwijst. De aanroeper blijft verantwoordelijk voor registratie bij het register, met behoud van de lock-semantiek en de warmup-pijplijn.

TypeSoortBelangrijkste ledenStabiliteitSinds
FontInfofinal readonly class$family, $style, $type, $unitsPerEm, $widths, $unicodeMap, $cmapForward, $fileData, $variationAxes, $kernPairs, getKey(), encodeText()stabiel1.0.0
FontTypeenum (string)TrueType, TrueTypeUnicode, OpenType, Type1, CidFont0stabiel1.0.0
Base14SubstituteFontsfinal class (intern)genormaliseerde Base 14-sleutel naar het pad van een meegeleverd Liberation-bestandstabiel2.7.0
ShaperFactoryfinal classdefault(), create(), wouldUseRealShaper()stabiel3.2.0
ShapingResultfinal readonly class$glyphRuns, $originalText, $script, $direction, $shaperImplstabiel3.2.0

Base14SubstituteFonts is @internal: uitsluitend voor framework-gebruik, zonder garantie dat het oppervlak ervan achterwaarts compatibel blijft.

examples/35-cjk-cmap-demo.php
<?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);

De parser vult FontInfo in en wijst het FontType toe. Een TrueType-lettertype met een Unicode-tekentoewijzing wordt TrueTypeUnicode; de writer voert dat uit als een samengesteld Type 0-lettertype.

examples/font/base14-fallback.php
<?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);
}
}
}

De resolver heeft geen neveneffecten. Registratie blijft expliciet, zodat de lock- en warmup-contracten van het register intact blijven. Symbol en ZapfDingbats geven bewust geen pad terug.

  • Symbol en ZapfDingbats worden opzettelijk niet gesubstitueerd. Een null-resultaat voor die sleutels is het gedocumenteerde gedrag, geen fout door een ontbrekend lettertype.
  • FontInfo is final readonly. Behandel een geparseerd lettertype als een waarde: verwacht nooit dat je breedtes of metrieken ter plekke muteert; registreer opnieuw als de bron verandert.
  • Een Type 1-lettertype heeft zowel de PFB-omtrek als de AFM-metrieken nodig. FontRegistry::registerType1() neemt het paar; automatische detectie leidt het AFM-pad af uit het PFB-pad op basis van de extensie.
  • FontType::TrueType en FontType::TrueTypeUnicode markeren het onderscheid tussen single-byte en multi-byte. De encoding-resolver gebruikt de ingevulde voorwaartse tekentoewijzing, niet de familienaam, zodat een Unicode-TrueType-lettertype automatisch naar het Identity-H-pad wordt geleid.
  • Variatie-lettertype-assen en benoemde instanties worden in FontInfo geparseerd als ze aanwezig zijn, maar het uitgewerkte voorbeeld voor Chinees, Japans en Koreaans (CJK) gebruikt bewust het statische lettertype om de geparseerde FontInfo deterministisch te houden.

Het register alloceert FontInfo eenmaal per lettertype per proces en deelt het daarna via referentie. Ruwe lettertype-bytes bepalen grotendeels de geheugenkosten. Warm alleen de lettertypen op die een worker nodig heeft en houd memoryUsage() bij. De Base 14-substitutieresolver voert een map-lookup in constante tijd uit zonder input/output (I/O) totdat de aanroeper het opgeloste bestand registreert. Het performance_budget van 1500 ms wandtijd en 64 MB piek dekt een typische warmup van een lettertypeset plus weergave. Totdat de subsetter draait, schaalt de geheugenvoetafdruk van elk lettertype mee met de bestandsgrootte van het lettertype, niet met het aantal glyphs.

FontInfo zelf is inert: geparseerde gegevens zonder gedrag buiten de pure encodeText()-transformatie. Het aanvalsoppervlak ligt stroomopwaarts, tijdens het parsen, wanneer willekeurige lettertype-bytes de TrueType- of Type 1-parser bereiken. De parsers controleren de grenzen van elke binaire offset en weigeren stream-wrappers en null-bytes in paden. Vóór registratie moet niet-vertrouwde lettertype-invoer door een beleid voor externe bronnen worden gevalideerd dat de grootte en het aantal glyphs begrenst. De meegeleverde Liberation-substituties zijn vertrouwde assets die met het pakket worden geleverd, dus het fallback-pad introduceert geen nieuwe niet-vertrouwde invoer.

BeweringStandaardClausuleBewijs
Elk lettertype dat het document gebruikt, wordt ingebed zodat het document wordt weergegeven zonder afhankelijk te zijn van systeemlettertypen.ISO 32000-2§9
Een TrueType-programma wordt ingebed via FontFile2 met de tabellen glyf, head, hhea, hmtx, loca, maxp.ISO 32000-2§9.6.5RAG-digest afgekapt door licentielimiet; prefix 7b26f37996239b2a, zie _downgraded-claims-o3.md
Een OpenType-programma (CFF) wordt ingebed via FontFile3.ISO 32000-2§9.6.5RAG-digest afgekapt door licentielimiet; prefix 801549ee00623baf, zie _downgraded-claims-o3.md

De eerste clausule is met een digest vastgepind en bevestigd door B1. De FontFile2- en FontFile3-clausules zijn parafrasen. De volledige RAG-digests voor die clausules zijn niet geretourneerd (afkapping door licentielimiet), dus het bewijs wordt ook bevestigd door FontSubsetter (die precies de set glyf/head/hhea/hmtx/loca/maxp opnieuw opbouwt) en de FontType-enum. NextPDF reproduceert geen normatieve tekst. In de broncode citeert Base14SubstituteFonts ISO 32000-2 §9.6.2.2 (verwerking van standaard Type 1-lettertypen), ISO 14289-2:2024 §8.4.5.5.1 (PDF/UA-2 lettertype-inbedding) en ISO 19005-4:2020 §6.3.5 (PDF/A-4 lettertype-inbedding). De pagina’s over toegankelijkheid en conformiteit bevatten de volledige profielconformiteit.

Een commercieel pakket voor lettertypelicenties en een dynamische subsetting-service bouwen voort op Core FontInfo en het register. De Core-lettertypemodule kan zonder licentie inbedden, subsets maken en fallback uitvoeren. De weggelaten conversielink is opzettelijk.