ข้ามไปยังเนื้อหา
getnextpdf.com

ความเสถียร: ทดลอง

ส่วนขยาย Retained page buffer

ส่วนขยายแบบ opt-in ไม่ใช่ความเท่าเทียมกับของดั้งเดิม อาร์กิวเมนต์ตัวสร้างนี้ ไม่มีอยู่ใน TCPDF 6.x ดั้งเดิม มันเป็นส่วนขยายของ NextPDF มันเปิดเป็นค่าเริ่มต้นปิด; เมื่อมันปิด adapter ทำงานเหมือนเดิมทุกประการ และ setPage() ไปยังหน้าก่อนหน้า จะยก UnsupportedFeatureException อย่างที่มันเป็นมาตลอด

TCPDF ดั้งเดิมให้คุณเรียก setPage() เพื่อย้อนกลับไปยังหน้าก่อนหน้าและวาดต่อ streaming adapter ทำเช่นนั้นไม่ได้โดยค่าเริ่มต้น — เมื่อหน้าถูก flush แล้ว มันก็หายไป — ดังนั้น setPage() หรือ lastPage() ไปยังหน้าก่อนหน้าจะยก UnsupportedFeatureException retained page buffer คือ opt-in ที่คืนพฤติกรรม back-fill นี้บน retained page buffer ของ NextPDF core

ส่ง retainedPageBuffer: true ไปยังตัวสร้างของ adapter เมื่อบัฟเฟอร์เปิด การเรียก setPage() หรือ lastPage() ที่เล็งไปยังหน้าก่อนหน้าจะมอบหมายให้ core back-fill แทน ที่จะยก:

<?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');

เหตุผลทั่วไปในการใช้บัฟเฟอร์คือ หน้าปกหรือหน้าสรุปที่ตัวเลขรู้ได้หลังจากจัดเนื้อหา แล้วเท่านั้น — จำนวนหน้าทั้งหมด ยอดรวม จำนวนระเบียน จองหน้า 1 ไว้ล่วงหน้า เรนเดอร์ เนื้อหา จากนั้น back-fill หน้าปกด้วย setPage(1) และกลับมาทำงานต่อตอนท้ายด้วย lastPage() ตัวอย่างนี้ยังแสดงขอบเขต fail-closed สองอย่างที่คุณต้องจัดการ: UnsupportedFeatureException ของ adapter สำหรับหมายเลขหน้าที่อยู่นอกช่วง และ RetainedPageBufferIncompatibleException ของ core หากเอกสารยังเปิดใช้คุณสมบัติ ที่เข้ากันไม่ได้ด้วย

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

แยกแยะพื้นผิวความล้มเหลวสองอย่างอย่างจงใจ:

  • UnsupportedFeatureException (adapter) — เป้าหมาย setPage() / lastPage() ที่ อยู่นอกช่วง หรือ การสลับไปหน้าก่อนหน้าใด ๆ เมื่อบัฟเฟอร์ ปิด
  • RetainedPageBufferIncompatibleException (core, NextPDF\Exception\Strict) — บัฟเฟอร์ เปิด แต่ถูกรวมกับคุณสมบัติที่เมตาดาทาระดับหน้าไม่สามารถ re-derive ได้หลัง back-fill ไม่มีชนิด RetainedPageBufferInconsistency; นี่คือ ข้อยกเว้นความไม่เข้ากันเดียว และการเกินงบประมาณปรากฏเป็น \OverflowException

adapter มอบหมายให้ core retained page buffer ดังนั้นการปฏิเสธเดียวกันจึงใช้บังคับ back-fill ถูกปฏิเสธ — โดยไม่ขึ้นกับลำดับและก่อน serialization — เมื่อเอกสารยังใช้สิ่ง ใดสิ่งหนึ่งในนี้ด้วย:

  • ลายเซ็นดิจิทัล
  • Tagged PDF (structure tree)
  • PDF/A
  • Linearization
  • การแพ็ค object stream
  • การเข้ารหัส
  • โหมดการเรนเดอร์ CSS แบบ Safe

การปฏิเสธแต่ละอย่างเป็นข้อยกเว้นแบบมีชนิดและ fail-closed — ไม่ใช่การตัดทิ้งที่เงียบ ๆ:

  • การรวมบัฟเฟอร์กับคุณสมบัติใด ๆ ข้างต้นจะยก core RetainedPageBufferIncompatibleException (เนมสเปซ NextPDF\Exception\Strict, @since core 6.1.0) การตรวจสอบไม่ขึ้นกับลำดับ: มันทำงานไม่ว่าคุณสมบัติที่เข้ากัน ไม่ได้จะถูกกำหนดค่าก่อนหรือหลัง opt-in บัฟเฟอร์
  • งบประมาณไบต์ที่ไม่บีบอัด 16 MiB ต่อเอกสารกำหนดขอบเขตบัฟเฟอร์; การเกินมัน จะยก \OverflowException ในเวลา build แทนที่จะตัดทิ้งหน้าที่ back-fill แล้ว

ประเด็นของการปฏิเสธคือ back-fill ไม่มีทางเปลี่ยนแปลงเอกสารที่ลงนามหรือเข้ารหัส อย่างเงียบ ๆ — สองสิ่งนี้เปิดพร้อมกันไม่ได้

  • เปิดเป็นค่าเริ่มต้นปิด สร้างโดยไม่มีแฟล็กแล้ว adapter ไม่เปลี่ยนแปลง; setPage() ไปยังหน้าก่อนหน้ายังยก UnsupportedFeatureException สิ่งนี้รักษา สัญญา streaming สำหรับผู้เรียกใช้ที่มีอยู่ทุกราย
  • ไม่ใช่ความเท่าเทียมกับของดั้งเดิม TCPDF ดั้งเดิมไม่มีแฟล็กตัวสร้าง retainedPageBuffer บันทึกสิ่งนี้เป็นส่วนขยายของ NextPDF เมื่อคุณ migrate เพื่อไม่ให้ผู้อ่านในอนาคตเข้าใจผิดว่ามันเป็นคุณสมบัติของ TCPDF
  • lastPage() กลับไปยังท้าย หลัง back-fill ให้เรียก lastPage() เพื่อทำงานต่อ ในการต่อท้ายที่หน้าสุดท้าย
  • วางแผนหนึ่งโหมด หากเอกสารต้องลงนาม tagged, PDF/A, linearized, เข้ารหัส หรือ object-stream อย่าเปิดบัฟเฟอร์; คำนวณค่าที่คุณจะ back-fill ล่วงหน้าแทน