Motores de layout personalizados e interceptación de texto durante el layout
De un vistazo
Sección titulada «De un vistazo»NextPDF no expone una interfaz conectable para motores de layout. El contrato público de extensión del layout es TextPreprocessorInterface, que intercepta texto durante el layout. También están disponibles los eventos de ciclo de vida del contenido, que permiten observar lo que produce el layout.
Instalación
Sección titulada «Instalación»composer require nextpdf/core:^3Resumen conceptual
Sección titulada «Resumen conceptual»La canalización de layout es interna. Abarca el layout de glifos, la creación de subconjuntos de fuentes, la salida del CMap ToUnicode y el árbol de estructura, y NextPDF no permite reemplazarla. La estabilidad de la salida en bytes y la conformidad con PDF etiquetado dependen de una sola compilación controlada.
Lo que NextPDF sí expone es el punto previo al layout: TextPreprocessorInterface. Una implementación recibe texto en bruto y devuelve un resultado segmentado antes de que ese texto entre en el layout de glifos, la creación de subconjuntos de fuentes, el CMap ToUnicode o el árbol de estructura. Esta es la forma admitida de cambiar el contenido de texto sin tocar el motor de layout.
El contrato incluye una regla estricta en su PHPDoc de origen: una implementación no debe cambiar el funcionamiento del layout. No debe añadir caracteres que afecten al layout, como el salto de línea, el retorno de carro o el tabulador, y debe mantener el orden lógico de lectura. El preprocesador declara un intercambio de contenido; no toma decisiones de layout. Respetar esta regla es necesario para no romper la salida estable ni la accesibilidad.
Para observar el resultado del layout —no para cambiarlo— se deben usar los eventos de ciclo de vida del contenido en Disparadores de acciones y escuchadores de eventos. ContentRenderedEvent se dispara después de dibujar el contenido en una página. FontLoadedEvent se dispara una vez por familia y estilo de fuente.
Superficie de la API
Sección titulada «Superficie de la API»NextPDF\Contracts\TextPreprocessorInterface (estable, desde la 1.9.0):
| Método | Devuelve | Propósito |
|---|---|---|
process(string $text) | TextPreprocessResult | Transforma el texto en bruto antes de la canalización de renderizado; devuelve un resultado segmentado con metadatos de redacción. |
El NextPDF\Contracts\TextPreprocessResult devuelto es un objeto de valor congelado. La firma de su constructor y sus propiedades públicas son estables, y no cambian en una versión menor ni de parche. Se pueden añadir nuevos métodos.
Ejemplo de código — Inicio rápido
Sección titulada «Ejemplo de código — Inicio rápido»Este pequeño preprocesador enmascara un token fijo. No añade caracteres que afecten al layout y mantiene el orden de lectura.
<?php
declare(strict_types=1);
use NextPDF\Contracts\TextPreprocessorInterface;use NextPDF\Contracts\TextPreprocessResult;use NextPDF\Contracts\TextSegment;
final class TokenMaskingPreprocessor implements TextPreprocessorInterface{ public function process(string $text): TextPreprocessResult { $masked = \str_replace('SECRET-TOKEN', '••••••••••••', $text);
return new TextPreprocessResult([ new TextSegment($masked, redacted: $masked !== $text), ]); }}Ejemplo de código — Producción
Sección titulada «Ejemplo de código — Producción»Un preprocesador de producción mantiene las reglas de coincidencia en un solo lugar. Falla de forma segura ante un patrón incorrecto y nunca registra el texto original.
<?php
declare(strict_types=1);
use NextPDF\Contracts\TextPreprocessorInterface;use NextPDF\Contracts\TextPreprocessResult;use NextPDF\Contracts\TextSegment;use Psr\Log\LoggerInterface;
final class PatternRedactionPreprocessor implements TextPreprocessorInterface{ /** * @param non-empty-string $pattern A valid PCRE pattern for sensitive spans */ public function __construct( private readonly string $pattern, private readonly LoggerInterface $logger, ) {}
public function process(string $text): TextPreprocessResult { $result = \preg_replace($this->pattern, '[REDACTED]', $text);
if ($result === null) { // Fail closed: never emit unredacted text on a pattern error. $this->logger->error('Redaction pattern failed; substituting empty text');
return new TextPreprocessResult([new TextSegment('', redacted: true)]); }
return new TextPreprocessResult([ new TextSegment($result, redacted: $result !== $text), ]); }}Casos límite y trampas
Sección titulada «Casos límite y trampas»- Sin reemplazo del layout. No hay contrato para reemplazar el layout de cajas, el salto de líneas ni la paginación. La petición de conectar un motor de layout de terceros queda fuera del alcance por diseño.
- Cumplimiento de la regla. Añadir
\n,\ro\tenprocess()corrompe el layout y rompe la salida estable. El motor confía en la regla; no vuelve a comprobar tu salida en busca de caracteres que afecten al layout. - Orden de lectura. Reordenar los segmentos rompe el orden de lectura del PDF etiquetado y la conformidad con PDF/UA.
- Una sola responsabilidad. El preprocesador declara un intercambio de contenido. Usar los eventos de ciclo de vida para observar, y no introducir efectos secundarios a través de
process().
Rendimiento
Sección titulada «Rendimiento»process() se ejecuta una vez por cada serie de texto en la ruta crítica del layout. Debe mantenerse ligero en memoria. Compilar los patrones una sola vez en el constructor, no en cada llamada. Los eventos de ciclo de vida del contenido no tienen coste cuando no hay ningún escuchador asociado.
Notas de seguridad
Sección titulada «Notas de seguridad»TextPreprocessorInterface es el lugar admitido para eliminar contenido sensible antes de que llegue al flujo de contenido, los subconjuntos de fuentes o los metadatos. Como se ejecuta antes de la creación de subconjuntos y del CMap ToUnicode, los glifos redactados nunca entran en el archivo. Un fallo del preprocesador debe tratarse como falla-segura, y debe usarse texto vacío o enmascarado en lugar de emitir el original.
Conformidad
Sección titulada «Conformidad»Ninguna afirmación normativa de firma ni de archivado se aplica a esta página. La regla de orden de lectura alinea el contrato con las necesidades del PDF etiquetado. La conformidad en el nivel de etiquetas se cubre en la referencia de accesibilidad.
Contexto comercial
Sección titulada «Contexto comercial»NextPDF Pro ofrece estrategias de preprocesamiento de texto para producción, incluida la redacción de PII ajustada a los tipos de documento más comunes. En Core se implementa TextPreprocessorInterface directamente, o se usa una compilación verificada de una edición de pago a través del mismo contrato público.
Véase también
Sección titulada «Véase también»- Introducción a la creación de extensiones
- Disparadores de acciones y escuchadores de eventos
- Fuentes personalizadas
- Reglas de estabilidad del SPI
Contratos y módulos relacionados
Sección titulada «Contratos y módulos relacionados»- Referencia de contratos de tipografía — donde se documentan
TextPreprocessorInterfaceyTextPreprocessResult. - Referencia de contratos de streaming — los contratos
experimentalCursorInterfaceyStreamingWriterInterface, que ya cuentan con una implementación de motor disponible. - Disparadores de acciones y escuchadores de eventos — los eventos de ciclo de vida que se usan para observar la salida del layout.
- Reglas de estabilidad del SPI — la promesa de objeto de valor congelado detrás de
TextPreprocessResult. - Introducción a la creación de extensiones — la superficie completa del SPI público.
El glosario define text preprocessor y extension point; consultar el glosario publicado para cada definición canónica.