Incorporer une police TrueType sous forme de sous-ensemble
Enregistre une police TrueType, utilise-la pour le rendu du texte et laisse le writer incorporer un sous-ensemble de la police. Cette recette suit le même chemin de traitement du contenu que examples/04-text-and-fonts.php, avec en plus une police TrueType (.ttf) enregistrée.
Installation
Section intitulée « Installation »composer require nextpdf/core:^3Cette contrainte cible le package nextpdf/core, et l’exemple s’exécute avec PHP 8.4. La fixture de test LiberationSans-Regular.ttf fournie rend cette recette autonome.
Vue d’ensemble conceptuelle
Section intitulée « Vue d’ensemble conceptuelle »Enregistre une police avec FontRegistry::register($path, $alias). Le registry analyse le fichier et renvoie un FontInfo, en s’appuyant sur TrueTypeParser pour les fichiers .ttf et .otf. Pour utiliser cette police, sélectionne son alias avec setFont($alias, ...). Cet appel mémorise aussi les codepoints utilisés.
La mise en sous-ensemble s’exécute automatiquement à l’appel de save(). Le writer de polices PDF collecte les codepoints utilisés et appelle FontSubsetter::subset(), ou CffSubsetter pour les polices Compact Font Format (CFF) ou OpenType. Quand le sous-ensemble est plus petit que le programme complet, le writer l’incorpore et réécrit BaseFont et FontName avec un tag de sous-ensemble de six lettres majuscules suivi d’un signe plus. C’est la forme ABCDEF+FontName qu’ISO 32000-2 exige pour un sous-ensemble de police. Le writer stocke le programme TrueType incorporé sous forme de FontFile2 dans le descripteur de police (ISO 32000-2).
Le préfixe de sous-ensemble est généré de façon déterministe à partir du nom PostScript, si bien qu’un build déterministe produit un tag stable. C’est pourquoi le profil de reproductibilité de la recette est structural. Le profil structural normalise le préfixe de sous-ensemble et le /ID du trailer plutôt que de les vérifier à l’octet près.
Surface d’API
Section intitulée « Surface d’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; passe l’alias enregistré comme$family.- La mise en sous-ensemble est interne au writer (
NextPDF\Writer\PdfFontWriter->NextPDF\Typography\FontSubsetter). Il n’existe pas d’interrupteur public d’activation ou de désactivation : le writer met toujours en sous-ensemble quand les codepoints sont connus et que le sous-ensemble est plus petit.
Le tableau PHPDoc complet est généré à partir des sources.
Exemple de code — Démarrage rapide
Section intitulée « Exemple de code — Démarrage rapide »<?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() construit son propre registry. Pour utiliser un registry que tu as peuplé toi-même, construis le document via DocumentFactory, comme le montre l’exemple de production. La factory garantit que le writer lit la police enregistrée dans ce registry.
Exemple de code — Production
Section intitulée « Exemple de code — Production »Cet exemple est autonome et exécutable dans le harness. Il enregistre le fichier LiberationSans-Regular.ttf fourni et effectue le rendu via DocumentFactory, afin que le registry peuplé soit bien celui qui est utilisé, puis il s’appuie sur la mise en sous-ensemble automatique au moment de la sauvegarde.
<?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";Sortie STDOUT attendue :
Wrote embed-and-subset-fonts.pdfPour confirmer la mise en sous-ensemble, ouvre le fichier produit et inspecte le dictionnaire de polices. Le BaseFont affiche <TAG>+LiberationSans, et le descripteur contient un FontFile2. L’exécution de qpdf --check ne signale aucune erreur structurelle.
Cas limites & pièges
Section intitulée « Cas limites & pièges »- Propriété du registry.
Document::createStandalone()construit son propre registry. Une police que tu as enregistrée dans unFontRegistrydistinct n’est pas visible pour lui. UtiliseDocumentFactorypour passer ton registry, comme le fait l’exemple de production. - Droits d’incorporation. La mise en sous-ensemble ne modifie pas la licence. N’incorpore que des polices que tu es autorisé à incorporer. Certaines polices définissent des bits de restriction d’incorporation ; le parser les lit, mais tu restes responsable de la conformité.
- Chemin CFF/OpenType. Les polices
.otfet CFF sont mises en sous-ensemble parCffSubsetter, et non parFontSubsetter. Le comportement et la réécriture du tag de sous-ensemble sont équivalents ; seul le chemin de code diffère. - Aucun gain de taille. Parfois, le sous-ensemble n’est pas plus petit que l’original, ce qui peut arriver avec de petites polices ou quand tous les glyphes sont utilisés. Dans ce cas, le writer incorpore le programme original sans tag de sous-ensemble. Ce comportement est correct ; ce n’est pas un échec.
- Polices CJK. Les grandes polices chinoises, japonaises et coréennes (CJK) utilisent une stratégie de mise en sous-ensemble par paliers selon ADR-008, avec un sous-processus isolé et un repli PHP natif. Consulte Composer du texte CJK avec un encodage tenant compte de la cmap pour connaître les spécificités CJK et l’état actuel du pipeline.
Performance
Section intitulée « Performance »L’analyse parcourt une seule fois les tables de la police, et le coût de la mise en sous-ensemble augmente avec le nombre de glyphes. Les polices latines non-CJK sont mises en sous-ensemble dans le processus courant, dans le budget wall_ms: 1500, peak_mb: 96. Les grandes polices CJK sont routées vers un sous-processus isolé avec un délai d’attente en temps réel de deux secondes et un repli PHP natif (ADR-008). Ce routage signifie qu’une mise en sous-ensemble lente ou qui plante ne peut pas bloquer l’appelant.
Notes de sécurité
Section intitulée « Notes de sécurité »Un fichier de police est une entrée binaire non fiable. Le parser rejette les chemins contenant un wrapper de flux et les octets nuls. Le sous-processus de mise en sous-ensemble CJK s’exécute sans hériter de connexions de base de données, de handles de fichiers ou de l’état du framework, et il se replie en toute sécurité en cas de plantage ou de dépassement du délai (ADR-008). Valide la provenance des polices acceptées depuis les utilisateurs finaux.
Conformité
Section intitulée « Conformité »| Déclaration | Spécification | Clause | reference_id |
|---|---|---|---|
| Le BaseFont/FontName d’un sous-ensemble de police porte un préfixe de sous-ensemble de six lettres majuscules, joint par un plus. | ISO 32000-2 | iso32000_2_sec9#x1.x66.p2 | |
| Un programme de police TrueType incorporé est stocké sous forme de FontFile2 dans le descripteur de police. | ISO 32000-2 | iso32000_2_sec9#x1.x65.p15 |
Cette recette montre comment NextPDF incorpore et met en sous-ensemble une police TrueType, puis émet un préfixe de sous-ensemble conforme. Elle n’affirme pas la conformité de licence des polices, et les droits d’incorporation relèvent de la responsabilité de l’intégrateur.
Contexte commercial
Section intitulée « Contexte commercial »Non applicable.