Contratos / Tipografía
En resumen
Sección titulada «En resumen»El dominio de tipografía incluye el contrato del registro de fuentes y los contratos de preprocesamiento de texto: FontRegistryInterface, TextPreprocessorInterface y los objetos de valor inmutables TextPreprocessResult y TextSegment. Todos son stable.
Instalación
Sección titulada «Instalación»composer require nextpdf/core:^3Panorama conceptual
Sección titulada «Panorama conceptual»FontRegistryInterface es el almacén de fuentes con vida durante todo el proceso. Registra una fuente TrueType, OpenType, TTC o PFB y devuelve los metadatos FontInfo ya analizados. El registro pervive más allá de los documentos individuales, de modo que un worker analiza cada fuente una sola vez. Permite precargar un lote de fuentes durante el arranque y luego bloquearse para que el tráfico de producción no pueda modificarlo. Un registro bloqueado lanza LogicException en register(), addFontDirectory() o warmup(), mientras que las consultas siguen disponibles. El registro también acepta una fuente a partir de bytes en bruto mediante registerFromBinary(). El puente de @font-face usa este método para registrar una fuente obtenida desde un origen remoto o un URI de datos. El registro contiene solo datos PHP puros (sin handles de recursos), por lo que se puede compartir de forma segura entre un grupo de workers.
El motor incrusta cada fuente que utiliza y crea un subconjunto de ella. Un programa de fuente incrustado se incluye dentro del PDF, de modo que el documento se representa igual en cualquier visor, con independencia de las fuentes del sistema instaladas — ISO 32000-2 §9. Un subconjunto de fuente solo incluye los glifos que el documento referencia realmente, lo que resulta clave para contenido CJK o con abundante Unicode — ISO 32000-2 §9. El contrato del registro expone los metadatos analizados que consumen las etapas de creación de subconjuntos e incrustación.
TextPreprocessorInterface intercepta el texto antes de que entre en la composición de glifos, el subconjunto de fuentes, el CMap ToUnicode y el árbol de estructura. Esta ubicación es la propiedad de seguridad clave: un preprocesador que aplica redacción al contenido lo elimina antes de que pueda llegar al flujo de contenido, al subconjunto de fuente o a los metadatos. El contrato impone dos invariantes. Un preprocesador no debe introducir caracteres que afecten al diseño y debe preservar el orden lógico de lectura; su responsabilidad es la sustitución de contenido, no el diseño. El resultado es un TextPreprocessResult inmutable que contiene una lista ordenada de valores TextSegment. Un segmento es de paso directo o de redacción. Para un segmento redactado, el texto que se muestra depende del modo de enmascaramiento: vacío para un rectángulo de caja negra, asteriscos que igualan la longitud del original o una etiqueta fija. El originalCharCount de un segmento es una pista de medición no reversible que solo se usa para dimensionar un rectángulo de redacción. Nunca debe usarse para reconstruir el contenido original.
Superficie de API
Sección titulada «Superficie de API»| Tipo | Clase | Miembros clave | Estabilidad | Desde |
|---|---|---|---|---|
FontRegistryInterface | interface | register(), get(), has(), all(), addFontDirectory(), warmup(), lock(), isLocked(), registerBase14(), registerFromBinary(), memoryUsage() | stable | 1.7.0 |
TextPreprocessorInterface | interface | process(string): TextPreprocessResult | stable | 1.9.0 |
TextPreprocessResult | final readonly class | $segments, hasRedactions(), getDisplayText() | stable | 1.9.0 |
TextSegment | final readonly class | $displayText, $isRedacted, $originalCharCount, $fillColor | stable | 1.9.0 |
TextPreprocessResult y TextSegment fijan la firma de su constructor y sus propiedades públicas; se pueden añadir métodos nuevos, pero las propiedades no pueden cambiar.
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;
$doc = Document::createStandalone();$doc->addPage();$doc->setFont('helvetica', 'B', 18);$doc->cell(0, 12, 'Bold heading', newLine: true);$doc->setFont('helvetica', '', 11);$doc->multiCell(0, 7, 'Body text rendered with a registered font.');$doc->save(__DIR__ . '/output/04-text-and-fonts.pdf');setFont() resuelve la familia a través de FontRegistryInterface. El documento independiente usa un registro privado. Un worker comparte un registro (consulta la página del documento).
Ejemplo de código — Producción
Sección titulada «Ejemplo de código — Producción»<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\FontRegistryInterface;use NextPDF\Contracts\TextPreprocessorInterface;use NextPDF\Exception\NextPdfException;use Psr\Log\LoggerInterface;
final readonly class FontWarmupService{ public function __construct( private FontRegistryInterface $fonts, private TextPreprocessorInterface $preprocessor, private LoggerInterface $logger, ) {}
/** * Warm a font set at boot, then lock the registry. * * @param list<string> $fontFiles Absolute paths to font files. */ public function boot(array $fontFiles): void { try { $this->fonts->warmup($fontFiles); $this->fonts->lock(); } catch (NextPdfException $e) { $this->logger->error('Font warmup failed', ['error' => $e->getMessage()]);
throw $e; } }
public function redact(string $text): string { $result = $this->preprocessor->process($text);
return $result->hasRedactions() ? $result->getDisplayText() : $text; }}La secuencia de arranque del worker es warmup() y luego lock(). Después de lock(), cualquier mutación lanza una excepción. Las consultas siguen atendiendo el tráfico.
Casos límite y problemas frecuentes
Sección titulada «Casos límite y problemas frecuentes»- Un registro bloqueado rechaza todos los métodos de mutación. Precargar y bloquear en el arranque; nunca llamar a
register()durante el manejo de la solicitud. registerFromBinary()escribe los bytes de la fuente en un archivo temporal para analizarlos. Los datos de fuente no confiables son una superficie de ataque de análisis sintáctico: deben controlarse medianteExternalResourcePolicyInterface(consultar la página de política de seguridad).- Un
TextPreprocessorno debe añadir saltos de línea, retornos de carro ni tabulaciones. Hacerlo cambia el diseño y rompe la primera invariante del contrato. TextSegment::$originalCharCountes solo una pista de ancho. Usarla para inferir el contenido original anula la redacción y viola la tercera invariante del contrato.TextPreprocessResult::getDisplayText()devuelve una cadena vacía para los segmentos de caja negra por diseño. No tratar un segmento vacío como un fallo de preprocesamiento.
Rendimiento
Sección titulada «Rendimiento»El análisis de fuentes es el costo dominante del primer uso; el registro lo amortiza hasta una sola ejecución por proceso. Tras la precarga, get() y has() son búsquedas O(1) en el mapa. memoryUsage() devuelve un MemoryReport para que un worker pueda controlar la caché de fuentes respecto de su presupuesto. El preprocesamiento de texto es lineal en función de la longitud de la entrada. La lista de segmentos añade una sobrecarga acotada, proporcional al número de coincidencias de redacción. El performance_budget de 1500 ms de tiempo total y 64 MB de pico cubre la precarga de un conjunto de fuentes típico más la representación del documento. El costo del subconjunto escala con el número de glifos que realmente se usan, no con la tabla completa de glifos de la fuente. Por lo tanto, el subconjunto reduce el tamaño de salida y el costo de representación del contenido CJK.
Notas de seguridad
Sección titulada «Notas de seguridad»El dominio de tipografía tiene dos superficies relevantes para la seguridad. La primera es la entrada de fuentes: registerFromBinary() analiza bytes arbitrarios. Los datos de fuente no confiables deben pasar por un ExternalResourcePolicyInterface que acote el tamaño del archivo y el número de glifos antes de que lleguen al analizador. La segunda es la redacción: TextPreprocessorInterface se ubica antes de la composición de glifos, el subconjunto de fuentes, el CMap ToUnicode y el árbol de estructura, precisamente para que el contenido redactado nunca entre en el artefacto representado. Una redacción implementada como una superposición en el momento del pintado filtra el texto original en el flujo de contenido y en el subconjunto. La ubicación del contrato evita esa clase de defecto. La pista de medición de un segmento es deliberadamente no reversible. Debe tratarse como no confiable cualquier fuente o texto proporcionado externamente.
Conformidad
Sección titulada «Conformidad»| Afirmación | Norma | Cláusula | Evidencia |
|---|---|---|---|
| Cada fuente que usa el documento está incrustada, de modo que el documento se representa sin depender de las fuentes del sistema. | ISO 32000-2 | §9 | |
| La fuente incrustada se reduce a un subconjunto de los glifos que el documento referencia. | ISO 32000-2 | §9 |
Ambas cláusulas se presentan parafraseadas. NextPDF no reproduce el texto normativo. PDF/A-4 exige la incrustación de cada fuente. Esa conformidad se documenta en las páginas de extracción y accesibilidad.
Véase también
Sección titulada «Véase también»- Contratos: 41 interfaces públicas (SPI) — el panorama de la SPI y los niveles de estabilidad.
- Contratos / Documento — el papel del registro en el ciclo de vida del documento.
- Contratos / Política de seguridad —
ExternalResourcePolicyInterfacecontrola los bytes de fuente no confiables. - Tipografía — el módulo de composición y diseño de texto.
- Fuente — análisis, subconjunto e incrustación de fuentes.
- Texto — salida de texto que consume los resultados del preprocesador.