Een TrueType-lettertype insluiten en subsetten
In het kort
Sectie met titel “In het kort”Registreer een TrueType-lettertype, render er tekst mee en laat de writer alleen de benodigde subset insluiten. Dit recipe volgt hetzelfde contentpad als examples/04-text-and-fonts.php, maar voegt daar een geregistreerd TrueType-lettertype (.ttf) aan toe.
Installeren
Sectie met titel “Installeren”composer require nextpdf/core:^3Deze constraint installeert het pakket nextpdf/core. Het voorbeeld draait op PHP 8.4 en de meegeleverde testfixture LiberationSans-Regular.ttf zorgt ervoor dat het recipe zelfstandig blijft.
Conceptueel overzicht
Sectie met titel “Conceptueel overzicht”Registreer een lettertype met FontRegistry::register($path, $alias). De registry parseert het bestand, retourneert een FontInfo en gebruikt daarvoor TrueTypeParser voor .ttf- en .otf-bestanden. Selecteer de alias met setFont($alias, ...) om het lettertype te activeren. Deze aanroep registreert ook de gebruikte codepoints.
Subsetten verloopt automatisch bij save(). De PDF-lettertype-writer verzamelt de gebruikte codepoints en roept FontSubsetter::subset() aan; voor Compact Font Format (CFF)- of OpenType-lettertypen gebruikt hij CffSubsetter. Wanneer de subset kleiner is dan het volledige programma, sluit de writer de subset in. Daarnaast herschrijft hij BaseFont en FontName met een subset-tag van zes hoofdletters, samengevoegd met een plusteken. Dit is de vorm ABCDEF+FontName die ISO 32000-2 voor een lettertypesubset vereist. De writer slaat het ingesloten TrueType-programma op als FontFile2 in de font descriptor (ISO 32000-2).
De subset-prefix wordt deterministisch gegenereerd uit de PostScript-naam, zodat een deterministische build een stabiele tag oplevert. Daarom is het reproduceerbaarheidsprofiel van dit recipe structural. Dat structural-profiel normaliseert de subset-prefix en de trailer /ID in plaats van ze byte voor byte te toetsen.
API-oppervlak
Sectie met titel “API-oppervlak”FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfo—NextPDF\Typography\FontRegistry.setFont(string $family, string $style = '', float $size = 12.0): static—NextPDF\Core\Concerns\HasTypography; geef de geregistreerde alias door als$family.- Subsetten gebeurt intern in de writer (
NextPDF\Writer\PdfFontWriter->NextPDF\Typography\FontSubsetter). Er is geen publieke aan- of uitschakelaar: de writer maakt altijd een subset wanneer de codepoints bekend zijn en de subset kleiner is.
De volledige PHPDoc-tabel wordt uit de broncode gegenereerd.
Codevoorbeeld — Snelstart
Sectie met titel “Codevoorbeeld — Snelstart”<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;use NextPDF\Typography\FontRegistry;
$registry = new FontRegistry();$registry->register(__DIR__ . '/MyFont-Regular.ttf', alias: 'MyFont');
$doc = Document::createStandalone();$doc->addPage();$doc->setFont('MyFont', '', 14);$doc->cell(0, 10, 'Rendered with an embedded, subset TrueType face.', newLine: true);
$doc->save(__DIR__ . '/out.pdf');Document::createStandalone() maakt een eigen registry aan. Als je een registry wilt gebruiken die je zelf hebt gevuld, bouw je het document via DocumentFactory, zoals in het productievoorbeeld wordt getoond. De factory laat de writer je geregistreerde lettertype lezen.
Codevoorbeeld — Productie
Sectie met titel “Codevoorbeeld — Productie”Dit voorbeeld draait zelfstandig binnen de harness. Het registreert de meegeleverde LiberationSans-Regular.ttf en rendert via DocumentFactory, zodat de gevulde registry de actieve registry is. Het maakt gebruik van automatisch subsetten bij het opslaan.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\DocumentFactory;use NextPDF\Graphics\ImageRegistry;use NextPDF\Typography\FontRegistry;
// A bundled TrueType test fixture keeps this recipe self-contained.// Replace with a font you have the right to embed.$fontPath = __DIR__ . '/../../fonts/test-fixtures/LiberationSans/LiberationSans-Regular.ttf';if (!is_file($fontPath)) { // Fall back to the repository-relative fixture location. $fontPath = dirname(__DIR__, 2) . '/fonts/test-fixtures/LiberationSans/LiberationSans-Regular.ttf';}
$fontRegistry = new FontRegistry();$fontRegistry->register($fontPath, alias: 'LiberationSans');
$imageRegistry = new ImageRegistry(maxCacheBytes: 0);$documentFactory = new DocumentFactory($fontRegistry, $imageRegistry);
$doc = $documentFactory->create();$doc->setTitle('Embedded Subset Font');$doc->addPage();
$doc->setFont('LiberationSans', '', 20);$doc->cell(0, 14, 'Embedded TrueType face', newLine: true);
$doc->setFont('LiberationSans', '', 12);$doc->multiCell(0, 7, 'Only the glyphs used by this document are embedded. ' . 'The writer subsets the font program and rewrites the BaseFont with a ' . 'deterministic six-letter subset prefix, for example ABCDEF+LiberationSans.');
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');$doc->save($out !== false ? $out : __DIR__ . '/embed-and-subset-fonts.pdf');
echo "Wrote embed-and-subset-fonts.pdf\n";Verwachte STDOUT:
Wrote embed-and-subset-fonts.pdfOpen de uitvoer en inspecteer de font-dictionary om de subset te controleren. De BaseFont bevat <TAG>+LiberationSans en de descriptor bevat een FontFile2. qpdf --check meldt geen structurele fouten.
Randgevallen en valkuilen
Sectie met titel “Randgevallen en valkuilen”- Eigenaarschap van de registry.
Document::createStandalone()maakt een eigen registry aan. Een lettertype dat je op een afzonderlijkeFontRegistryhebt geregistreerd, is daarvoor niet zichtbaar. GebruikDocumentFactoryom je registry door te geven, zoals het productievoorbeeld doet. - Insluitrechten. Subsetten verandert de licentievoorwaarden niet. Sluit alleen lettertypen in waarvoor je een licentie hebt om ze in te sluiten. Sommige lettertypen zetten bits voor insluitbeperkingen; de parser leest die bits, maar je blijft verantwoordelijk voor de naleving.
- CFF/OpenType-pad.
.otf- en CFF-lettertypen worden gesubset doorCffSubsetter, niet doorFontSubsetter. Het gedrag en het herschrijven van de subset-tag zijn gelijkwaardig. Alleen het codepad verschilt. - Geen winst in bestandsgrootte. Soms is de subset niet kleiner dan het origineel. Dit kan gebeuren bij zeer kleine lettertypen of wanneer alle glyphs worden gebruikt. In dat geval sluit de writer het originele programma in zonder subset-tag. Dit is correct en geen fout.
- CJK-lettertypen. Grote Chinese, Japanse en Koreaanse (CJK) lettertypen gebruiken volgens ADR-008 een gelaagde subsetstrategie, met een geïsoleerd subproces en een PHP-native fallback. Zie CJK-tekst zetten met cmap-bewuste codering voor CJK-specifieke details en de huidige status van de pipeline.
Prestaties
Sectie met titel “Prestaties”Het parseren vergt één doorloop van de lettertypetabellen, en de kosten van het subsetten groeien met het aantal glyphs. Latijnse lettertypen zonder CJK worden in-process gesubset binnen het budget wall_ms: 1500, peak_mb: 96. Grote CJK-lettertypen worden naar een geïsoleerd subproces geleid met een wall-clock-time-out van twee seconden en een PHP-native fallback (ADR-008). Door deze routering kan een traag of vastlopend subsetproces de aanroeper niet blokkeren.
Beveiligingsopmerkingen
Sectie met titel “Beveiligingsopmerkingen”Een lettertypebestand is onvertrouwde binaire invoer. De parser weigert stream-wrapper-paden en null-bytes. Het CJK-subsetsubproces draait zonder overgeërfde databaseverbindingen, bestandshandles of frameworkstatus. Bij een crash of time-out valt het veilig terug (ADR-008). Valideer de herkomst van lettertypen die je van eindgebruikers accepteert.
Conformiteit
Sectie met titel “Conformiteit”| Bewering | Spec | Clausule | reference_id |
|---|---|---|---|
| De BaseFont/FontName van een lettertypesubset bevat een subset-prefix van zes hoofdletters, samengevoegd met een plusteken. | ISO 32000-2 | iso32000_2_sec9#x1.x66.p2 | |
| Een ingesloten TrueType-lettertypeprogramma wordt opgeslagen als FontFile2 in de font descriptor. | ISO 32000-2 | iso32000_2_sec9#x1.x65.p15 |
Dit recipe laat zien hoe NextPDF een TrueType-lettertype insluit, er een subset van maakt en een conforme subset-prefix uitschrijft. Het garandeert niet dat de lettertypelicentie wordt nageleefd. Insluitrechten zijn de verantwoordelijkheid van de integrator.
Commerciële context
Sectie met titel “Commerciële context”Niet van toepassing.