Incorporare un font TrueType e crearne il subset
In breve
Sezione intitolata “In breve”Registrare un font TrueType, usarlo per il rendering del testo e lasciare che il writer incorpori un subset del font. Questa ricetta segue lo stesso percorso di contenuto di examples/04-text-and-fonts.php, aggiungendo un font TrueType (.ttf) registrato.
Installazione
Sezione intitolata “Installazione”composer require nextpdf/core:^3Questo vincolo corrisponde al pacchetto nextpdf/core e l’esempio viene eseguito su PHP 8.4. Il fixture di test LiberationSans-Regular.ttf incluso rende questa ricetta autonoma.
Panoramica concettuale
Sezione intitolata “Panoramica concettuale”Registrare un font con FontRegistry::register($path, $alias). Il registry analizza il file e restituisce un FontInfo, usando TrueTypeParser per i file .ttf e .otf. Per attivare quel font, selezionarne l’alias con setFont($alias, ...). Questa chiamata registra anche i codepoint utilizzati.
La creazione del subset viene eseguita automaticamente durante save(). Il writer dei font PDF raccoglie i codepoint utilizzati e chiama FontSubsetter::subset(), oppure CffSubsetter per i font Compact Font Format (CFF) o OpenType. Quando il subset è più piccolo del programma completo, il writer incorpora il subset e riscrive BaseFont e FontName con un tag di subset composto da sei lettere maiuscole unite da un segno più. È la forma ABCDEF+FontName che ISO 32000-2 richiede per un subset di font. Il writer memorizza il programma TrueType incorporato come FontFile2 nel descrittore del font (ISO 32000-2).
Il prefisso del subset viene generato in modo deterministico a partire dal nome PostScript; di conseguenza, una build deterministica produce un tag stabile. Per questo motivo il profilo di riproducibilità della ricetta è structural. Il profilo structural normalizza il prefisso del subset e il /ID del trailer invece di verificarli byte per byte.
Superficie API
Sezione intitolata “Superficie API”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; passare l’alias registrato come$family.- La creazione del subset è interna al writer (
NextPDF\Writer\PdfFontWriter->NextPDF\Typography\FontSubsetter). Non esiste alcun interruttore pubblico per attivarla o disattivarla: il writer crea sempre il subset quando i codepoint sono noti e il subset è più piccolo.
La tabella PHPDoc completa viene generata dal codice sorgente.
Esempio di codice — Avvio rapido
Sezione intitolata “Esempio di codice — Avvio rapido”<?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() costruisce il proprio registry. Per utilizzare un registry popolato manualmente, creare il documento tramite DocumentFactory, come mostra l’esempio di produzione. La factory fa sì che il font registrato sia quello letto dal writer.
Esempio di codice — Produzione
Sezione intitolata “Esempio di codice — Produzione”Questo esempio è autonomo ed eseguibile tramite l’harness. Registra il LiberationSans-Regular.ttf incluso ed esegue il rendering tramite DocumentFactory; quindi il registry popolato è quello effettivamente in uso e il subset viene creato automaticamente al salvataggio.
<?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";STDOUT previsto:
Wrote embed-and-subset-fonts.pdfPer confermare il subset, aprire l’output ed esaminare il dizionario del font. Il BaseFont riporta <TAG>+LiberationSans e il descrittore include un FontFile2. L’esecuzione di qpdf --check non segnala errori strutturali.
Casi limite e insidie
Sezione intitolata “Casi limite e insidie”- Proprietà del registry.
Document::createStandalone()crea il proprio registry. Un font registrato in unFontRegistryseparato non è visibile a quel documento. UtilizzareDocumentFactoryper passare il proprio registry, come nell’esempio di produzione. - Diritti di incorporamento. La creazione del subset non modifica i diritti di licenza. Incorporare solo font per i quali si dispone di una licenza di incorporamento. Alcuni font impostano bit di restrizione dell’incorporamento; il parser li legge, ma la responsabilità della conformità rimane dell’utente.
- Percorso CFF/OpenType. I font
.otfe CFF vengono sottoposti al subset daCffSubsetter, non daFontSubsetter. Il comportamento e la riscrittura del tag di subset sono equivalenti; cambia solo il percorso di codice. - Nessun risparmio di dimensioni. A volte il subset non è più piccolo dell’originale; può accadere con font molto piccoli o quando vengono utilizzati tutti i glifi. In tal caso il writer incorpora il programma originale senza un tag di subset. Questo è corretto, non è un errore.
- Font CJK. I font cinesi, giapponesi e coreani (CJK) di grandi dimensioni utilizzano una strategia di creazione del subset a più livelli secondo ADR-008, con un sottoprocesso isolato e un fallback nativo PHP. Vedere Impostare il testo CJK con codifica cmap-aware per le specifiche CJK e lo stato corrente della pipeline.
Prestazioni
Sezione intitolata “Prestazioni”L’analisi consiste in un singolo passaggio sulle tabelle del font e il costo della creazione del subset cresce con il numero di glifi. I font latini non CJK vengono sottoposti al subset in-process entro il budget wall_ms: 1500, peak_mb: 96. I font CJK di grandi dimensioni vengono indirizzati a un sottoprocesso isolato con un timeout wall-clock di due secondi e un fallback nativo PHP (ADR-008). Questo instradamento impedisce che un subset lento o in crash possa bloccare il chiamante.
Note sulla sicurezza
Sezione intitolata “Note sulla sicurezza”Un file di font è un input binario non attendibile. Il parser rifiuta i percorsi con stream-wrapper e byte null. Il sottoprocesso di creazione del subset CJK viene eseguito senza connessioni al database, handle di file o stato del framework ereditati, ed esegue il fallback in modo sicuro in caso di crash o timeout (ADR-008). Verificare la provenienza dei font accettati dagli utenti finali.
Conformità
Sezione intitolata “Conformità”| Dichiarazione | Specifica | Clausola | reference_id |
|---|---|---|---|
| Il BaseFont/FontName di un subset di font riporta un prefisso di subset composto da sei lettere maiuscole unite da un segno più. | ISO 32000-2 | iso32000_2_sec9#x1.x66.p2 | |
| Un programma di font TrueType incorporato viene memorizzato come FontFile2 nel descrittore del font. | ISO 32000-2 | iso32000_2_sec9#x1.x65.p15 |
Questa ricetta mostra come NextPDF incorpora un font TrueType, ne crea il subset ed emette un prefisso di subset conforme. Non garantisce la conformità alla licenza del font: i diritti di incorporamento sono responsabilità dell’integratore.
Contesto commerciale
Sezione intitolata “Contesto commerciale”Non applicabile.