Incrustar y crear un subconjunto de una fuente TrueType
De un vistazo
Sección titulada «De un vistazo»Registrar una fuente TrueType, renderizar texto con ella y dejar que el escritor incruste un subconjunto de la tipografía. Esta receta sigue la misma ruta de contenido que examples/04-text-and-fonts.php, con una fuente TrueType (.ttf) registrada adicional.
Instalación
Sección titulada «Instalación»composer require nextpdf/core:^3Esta restricción coincide con el paquete nextpdf/core, y el ejemplo se ejecuta en PHP 8.4. El fixture de prueba incluido LiberationSans-Regular.ttf mantiene esta receta autocontenida.
Visión conceptual
Sección titulada «Visión conceptual»Registrar una tipografía con FontRegistry::register($path, $alias). El registro analiza el archivo y devuelve un FontInfo; usa TrueTypeParser para los archivos .ttf y .otf. Para activar esa tipografía, seleccionar su alias con setFont($alias, ...). Esta llamada también registra los puntos de código utilizados.
La creación de subconjuntos se ejecuta automáticamente en save(). El escritor de fuentes PDF recopila los puntos de código utilizados y llama a FontSubsetter::subset(), o a CffSubsetter para las tipografías Compact Font Format (CFF) u OpenType. Cuando el subconjunto es más pequeño que el programa completo, el escritor incrusta el subconjunto y reescribe BaseFont y FontName con una etiqueta de subconjunto de seis letras mayúsculas unida con un signo más. Este es el formato ABCDEF+FontName que ISO 32000-2 requiere para un subconjunto de fuente. El escritor almacena el programa TrueType incrustado como FontFile2 en el descriptor de fuente (ISO 32000-2).
El prefijo de subconjunto se genera de forma determinista a partir del nombre PostScript, de modo que una compilación determinista produce una etiqueta estable. Por eso el perfil de reproducibilidad de la receta es structural. El perfil structural normaliza y elimina el prefijo de subconjunto y el /ID del tráiler, en lugar de validarlos byte a byte.
Superficie de la API
Sección titulada «Superficie de la 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; pasa el alias registrado como$family.- La creación de subconjuntos es interna al escritor (
NextPDF\Writer\PdfFontWriter->NextPDF\Typography\FontSubsetter). No existe un interruptor público para activarla o desactivarla: el escritor siempre crea subconjuntos cuando los puntos de código se conocen y el subconjunto es más pequeño.
La tabla completa de PHPDoc se genera a partir del código fuente.
Ejemplo de código — Inicio rápido
Sección titulada «Ejemplo de código — Inicio rápido»<?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() construye su propio registro. Para usar un registro poblado previamente, construir el documento a través de DocumentFactory, como muestra el ejemplo de producción. La fábrica garantiza que el escritor lea la tipografía registrada.
Ejemplo de código — Producción
Sección titulada «Ejemplo de código — Producción»Este ejemplo es autocontenido y se puede ejecutar en el arnés de pruebas. Registra el archivo LiberationSans-Regular.ttf incluido y renderiza a través de DocumentFactory, de modo que se usa el registro poblado y se apoya en la creación automática de subconjuntos al guardar.
<?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";Salida esperada en STDOUT:
Wrote embed-and-subset-fonts.pdfPara confirmar el subconjunto, abrir la salida e inspeccionar el diccionario de fuentes. El BaseFont se lee como <TAG>+LiberationSans, y el descriptor lleva un FontFile2. Ejecutar qpdf --check no informa errores estructurales.
Casos límite y trampas
Sección titulada «Casos límite y trampas»- Propiedad del registro.
Document::createStandalone()construye su propio registro. Una fuente registrada en unFontRegistryaparte no es visible para él. UsarDocumentFactorypara pasar el registro, como hace el ejemplo de producción. - Derechos de incrustación. La creación de subconjuntos no cambia las condiciones de licencia. Incrustar únicamente fuentes con licencia de incrustación. Algunas fuentes establecen bits de restricción de incrustación; el analizador lee esos bits, pero la responsabilidad del cumplimiento sigue siendo del integrador.
- Ruta CFF/OpenType. Las tipografías
.otfy CFF se crean en subconjuntos medianteCffSubsetter, noFontSubsetter. El comportamiento y la reescritura de la etiqueta de subconjunto son equivalentes, y solo difiere la ruta de código. - Sin ahorro de tamaño. A veces el subconjunto no es más pequeño que el original, lo que ocurre con fuentes muy pequeñas o cuando se usan todos los glifos. En ese caso el escritor incrusta el programa original sin una etiqueta de subconjunto. Esto es correcto, no un fallo.
- Fuentes CJK. Las tipografías grandes de chino, japonés y coreano (CJK) usan una estrategia de creación de subconjuntos por niveles según ADR-008, con un subproceso aislado y un mecanismo de respaldo nativo de PHP. Consulta Componer texto CJK con codificación basada en cmap para conocer los detalles de CJK y el estado actual de la canalización.
Rendimiento
Sección titulada «Rendimiento»El análisis realiza una sola pasada sobre las tablas de la fuente, y el costo de la creación de subconjuntos crece con el número de glifos. La creación de subconjuntos de las tipografías latinas no CJK se realiza dentro del proceso, dentro del presupuesto wall_ms: 1500, peak_mb: 96. Las tipografías CJK grandes se enrutan a un subproceso aislado con un tiempo límite de reloj de pared de dos segundos y un mecanismo de respaldo nativo de PHP (ADR-008). Este enrutamiento significa que un subconjunto lento o con fallos no puede bloquear al código llamador.
Notas de seguridad
Sección titulada «Notas de seguridad»Un archivo de fuente es una entrada binaria no confiable. El analizador rechaza las rutas con envoltorios de flujo y bytes nulos. El subproceso de creación de subconjuntos CJK se ejecuta sin conexiones de base de datos, manejadores de archivos ni estado del framework heredados, y recurre de forma segura a un mecanismo de respaldo en caso de fallo o tiempo de espera agotado (ADR-008). Validar la procedencia de las fuentes aceptadas de usuarios finales.
Conformidad
Sección titulada «Conformidad»| Declaración | Especificación | Cláusula | reference_id |
|---|---|---|---|
| El BaseFont/FontName de un subconjunto de fuente lleva un prefijo de subconjunto de seis letras mayúsculas unido con un signo más. | ISO 32000-2 | iso32000_2_sec9#x1.x66.p2 | |
| Un programa de fuente TrueType incrustado se almacena como FontFile2 en el descriptor de fuente. | ISO 32000-2 | iso32000_2_sec9#x1.x65.p15 |
Esta receta muestra cómo NextPDF incrusta y crea subconjuntos de una tipografía TrueType y emite un prefijo de subconjunto conforme. No afirma el cumplimiento de la licencia de la fuente, y los derechos de incrustación son responsabilidad del integrador.
Contexto comercial
Sección titulada «Contexto comercial»No aplicable.