Salta ai contenuti
getnextpdf.com

stabilità: Sperimentale

Estensione del buffer di pagina mantenuto

Estensione opt-in, non parità legacy. Questo argomento del costruttore non esiste nel TCPDF 6.x legacy. È un’estensione NextPDF. È disattivato per impostazione predefinita; con esso spento, l’adattatore si comporta esattamente come prima, e setPage() verso una pagina precedente solleva UnsupportedFeatureException come ha sempre fatto.

Il TCPDF legacy ti consente di chiamare setPage() per tornare a una pagina precedente e continuare a disegnare. L’adattatore in streaming non può farlo per impostazione predefinita — una volta scaricata, una pagina è perduta — perciò setPage() o lastPage() verso una pagina precedente solleva UnsupportedFeatureException. Il buffer di pagina mantenuto è l’opt-in che ripristina questo comportamento di ripopolamento sopra il buffer di pagina mantenuto di NextPDF core.

Passa retainedPageBuffer: true al costruttore dell’adattatore. Con il buffer attivo, una chiamata setPage() o lastPage() che punta a una pagina precedente delega al ripopolamento di core invece di sollevare un’eccezione:

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF(retainedPageBuffer: true);
$pdf->AddPage(); // page 1 — reserve room for a running total
$pdf->Cell(0, 10, 'Invoice', ln: 1);
$pdf->AddPage(); // page 2 — line items
$pdf->Cell(0, 10, 'Line items…', ln: 1);
$total = 1234.56; // known only after the items are laid out
$pdf->setPage(1); // delegates to the core back-fill
$pdf->Cell(0, 10, 'Grand total: ' . number_format($total, 2), ln: 1);
$pdf->lastPage(); // return to the final page
$pdf->Output(__DIR__ . '/invoice.pdf', 'F');

Esempio di produzione: ripopolare una pagina di copertina riservata

Sezione intitolata “Esempio di produzione: ripopolare una pagina di copertina riservata”

Un motivo comune per ricorrere al buffer è una pagina di copertina o di riepilogo i cui numeri sono noti solo dopo che il corpo è stato disposto — un conteggio totale delle pagine, un totale generale, un conteggio dei record. Riserva la pagina 1 in anticipo, rendi il corpo, poi ripopola la copertina con setPage(1) e riprendi alla fine con lastPage(). Questo esempio mostra anche i due confini fail-closed che devi gestire: la UnsupportedFeatureException dell’adattatore per un numero di pagina fuori intervallo, e la RetainedPageBufferIncompatibleException di core se il documento abilita anche una funzionalità incompatibile.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\Exception\UnsupportedFeatureException;
use NextPDF\Compat\Tcpdf\TCPDF;
use NextPDF\Exception\Strict\RetainedPageBufferIncompatibleException;
/**
* Render a multi-page report whose cover page summarises figures that are
* only known once every body page has been laid out.
*
* @param list<array{label: string, amount: float}> $lineItems
*/
function renderReport(array $lineItems, string $destination): void
{
// Opt in to the back-fill buffer. Default-off; this is a NextPDF
// extension, not legacy TCPDF parity. (Underlying core feature: 6.1.0.)
$pdf = new TCPDF(retainedPageBuffer: true);
// Page 1 — the cover. Reserve it now; the summary is filled in last.
$pdf->AddPage();
$pdf->Cell(0, 10, 'Quarterly report', ln: 1);
// Body pages — lay out the line items, accumulating the running total.
$pdf->AddPage();
$total = 0.0;
foreach ($lineItems as $item) {
$total += $item['amount'];
$pdf->Cell(0, 8, $item['label'] . ': ' . number_format($item['amount'], 2), ln: 1);
}
// Back-fill the cover with figures known only now. setPage() delegates to
// the core back-fill in retained mode; an out-of-range page number still
// fails closed with UnsupportedFeatureException in BOTH modes.
try {
$pdf->setPage(1);
} catch (UnsupportedFeatureException $e) {
throw new RuntimeException('Cover page was not reserved: ' . $e->getMessage(), previous: $e);
}
$pdf->Cell(0, 10, 'Total: ' . number_format($total, 2), ln: 1);
$pdf->Cell(0, 10, 'Line items: ' . count($lineItems), ln: 1);
// Resume appending at the final page before output.
$pdf->lastPage();
// Output() drives the core build. If the document had also enabled a
// back-fill-incompatible feature (signing, tagging, PDF/A, linearization,
// object streams, encryption, Safe CSS mode), the core refuses here,
// order-independently, with RetainedPageBufferIncompatibleException — the
// back-fill can never silently corrupt such a document.
try {
$pdf->Output($destination, 'F');
} catch (RetainedPageBufferIncompatibleException $e) {
// $e->feature names the incompatible feature, e.g. 'signature'.
throw new RuntimeException(
'Back-fill is incompatible with ' . $e->feature . '; render pages in order instead.',
previous: $e,
);
}
}

Distingui deliberatamente le due superfici di fallimento:

  • UnsupportedFeatureException (adattatore) — un target setPage() / lastPage() fuori intervallo, o qualsiasi passaggio a una pagina precedente quando il buffer è spento.
  • RetainedPageBufferIncompatibleException (core, NextPDF\Exception\Strict) — il buffer è attivo ma combinato con una funzionalità i cui metadati a livello di pagina non possono essere riderivati dopo un ripopolamento. Non esiste alcun tipo RetainedPageBufferInconsistency; questa è l’unica eccezione di incompatibilità, e un superamento del budget emerge come \OverflowException.

L’adattatore delega al buffer di pagina mantenuto di core, perciò si applicano gli stessi rifiuti. Il ripopolamento è rifiutato — indipendentemente dall’ordine e prima della serializzazione — quando il documento usa anche una qualsiasi di:

  • Una firma digitale.
  • PDF taggato (albero della struttura).
  • PDF/A.
  • Linearizzazione.
  • Packing in object stream.
  • Cifratura.
  • Modalità di rendering CSS Safe.

Ogni rifiuto è un’eccezione tipizzata e fail-closed — mai uno scarto silenzioso:

  • Combinare il buffer con una qualsiasi funzionalità sopra solleva la RetainedPageBufferIncompatibleException di core (namespace NextPDF\Exception\Strict, @since core 6.1.0). Il controllo è indipendente dall’ordine: scatta sia che la funzionalità incompatibile sia stata configurata prima sia dopo l’opt-in del buffer.
  • Un budget di byte non compressi di 16 MiB per documento limita il buffer; superarlo solleva \OverflowException al momento della build invece di scartare una pagina ripopolata.

Il senso del rifiuto è che un ripopolamento non può mai alterare silenziosamente un documento firmato o cifrato — i due non possono essere abilitati insieme.

  • Disattivato per impostazione predefinita. Costruisci senza il flag e l’adattatore è invariato; setPage() verso una pagina precedente solleva ancora UnsupportedFeatureException. Questo preserva il contratto dello streaming per ogni chiamante esistente.
  • Non parità legacy. Il TCPDF legacy non ha alcun flag del costruttore retainedPageBuffer. Documenta questo come un’estensione NextPDF quando migri, affinché un lettore futuro non lo scambi per una funzionalità TCPDF.
  • lastPage() torna alla fine. Dopo un ripopolamento, chiama lastPage() per riprendere l’append all’ultima pagina.
  • Pianifica una sola modalità. Se il documento deve essere firmato, taggato, PDF/A, linearizzato, cifrato o con object stream, non abilitare il buffer; pre-calcola invece il valore che avresti ripopolato.