Salta ai contenuti

Motori di impaginazione personalizzati e intercettazione del testo durante il layout

NextPDF non espone un’interfaccia per collegare un motore di impaginazione. Il contratto pubblico per le estensioni di impaginazione è TextPreprocessorInterface, che si aggancia al testo durante il layout. Sono inoltre disponibili gli eventi del ciclo di vita del contenuto, che consentono di osservare ciò che l’impaginazione produce.

Terminal window
composer require nextpdf/core:^3

La pipeline di impaginazione è interna. Comprende il layout dei glifi, il subsetting dei font, l’output della CMap ToUnicode e l’albero della struttura, e NextPDF non ne consente la sostituzione. La stabilità dell’output a livello di byte e la conformità al PDF con tag si basano su un’unica build controllata.

Ciò che NextPDF espone è il punto precedente al layout: TextPreprocessorInterface. Un’implementazione riceve il testo grezzo e restituisce un risultato segmentato, prima che il testo entri nel layout dei glifi, nel subsetting dei font, nella CMap ToUnicode o nell’albero della struttura. Questo è il modo supportato per modificare il contenuto testuale senza intervenire sul motore di impaginazione.

Il contratto stabilisce una regola tassativa nel proprio PHPDoc di origine: un’implementazione non deve modificare il funzionamento del layout. Non deve aggiungere caratteri che influiscono sul layout, come avanzamento riga, ritorno a capo o tabulazione, e deve mantenere l’ordine di lettura logico. Il preprocessore dichiara una sostituzione di contenuto; non effettua scelte di impaginazione. Questa regola va rispettata, altrimenti si compromettono la stabilità dell’output e l’accessibilità.

Per osservare il risultato dell’impaginazione, non per modificarlo, utilizzare gli eventi del ciclo di vita del contenuto descritti in Trigger di azione e listener di eventi. ContentRenderedEvent viene attivato dopo che il contenuto è stato disegnato su una pagina. FontLoadedEvent viene attivato una volta per ogni combinazione di famiglia e stile di font.

NextPDF\Contracts\TextPreprocessorInterface (stabile, dalla versione 1.9.0):

MetodoValore restituitoScopo
process(string $text)TextPreprocessResultTrasforma il testo grezzo prima della pipeline di rendering; restituisce un risultato suddiviso in segmenti con i metadati di oscuramento.

L’oggetto NextPDF\Contracts\TextPreprocessResult restituito è un value object congelato. La firma del costruttore e le proprietà pubbliche sono stabili e non cambiano nelle release minor o patch. Possono essere aggiunti nuovi metodi.

Questo semplice preprocessore maschera un token fisso. Non aggiunge caratteri che influiscono sul layout e mantiene l’ordine di lettura.

<?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),
]);
}
}

Un preprocessore per la produzione centralizza le regole di corrispondenza. Adotta un comportamento fail-closed in caso di pattern non valido e non registra mai il testo originale.

<?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),
]);
}
}
  • Nessuna sostituzione del layout. Non esiste alcun contratto per sostituire il layout dei box, l’interruzione di riga o la paginazione. Collegare un motore di impaginazione di terze parti è volutamente fuori ambito.
  • Rispetto della regola. L’aggiunta di \n, \r o \t in process() danneggia il layout e compromette la stabilità dell’output. Il motore si affida alla regola; non ricontrolla l’output per individuare caratteri che influiscono sul layout.
  • Ordine di lettura. Il riordino dei segmenti compromette l’ordine di lettura del PDF con tag e la conformità a PDF/UA.
  • Una sola responsabilità. Il preprocessore dichiara una sostituzione di contenuto. Utilizzare gli eventi del ciclo di vita per l’osservazione e non introdurre effetti collaterali tramite process().

process() viene eseguito una volta per ogni text run nel percorso critico del layout. Mantenerlo leggero nell’uso della memoria. Compilare i pattern una sola volta nel costruttore, non a ogni chiamata. Gli eventi del ciclo di vita del contenuto non comportano alcun costo quando non è associato alcun listener.

TextPreprocessorInterface è il punto supportato per rimuovere i contenuti sensibili prima che raggiungano il flusso di contenuto, i subset di font o i metadati. Poiché viene eseguito prima del subsetting e della CMap ToUnicode, i glifi oscurati non entrano mai nel file. Gestire un errore del preprocessore in modalità fail-closed e utilizzare testo vuoto o mascherato anziché emettere l’originale.

A questa pagina non si applica alcuna dichiarazione normativa di firma o archiviazione. La regola sull’ordine di lettura allinea il contratto alle esigenze del PDF con tag. La conformità a livello di tag è trattata nel riferimento sull’accessibilità.

NextPDF Pro offre strategie di preelaborazione del testo pronte per la produzione, incluso l’oscuramento delle PII ottimizzato per i tipi di documento più comuni. Con Core si implementa TextPreprocessorInterface in autonomia, oppure si utilizza una build verificata dell’edizione a pagamento tramite lo stesso contratto pubblico.

Il glossario definisce text preprocessor ed extension point; per ciascuna definizione canonica, consultare il glossario pubblicato.