建立具備自動分頁的多頁文件
重點速覽
標題為「重點速覽」的區段建立一份內容橫跨多頁的文件。一邊建構文件,一邊加入內容。啟用 setAutoPageBreak() 後,當游標抵達底部邊界時,版面引擎會自動替你開新頁。呼叫 save() 之後,再用 getNumPages() 讀取最終頁數。本範例依循 examples/05-multi-page.php。
在 save() 期間,引擎會將每一頁的繪製標記寫入一個內容串流。ISO 32000-2 §7.7.3.3 將一頁的 Contents 定義為單一串流,或依序串接的串流陣列。因此,多頁輸出是一系列頁物件,而不是單一緩衝區。
composer require nextpdf/core:^3不需要任何選用擴充套件。本範例可在 PHP 8.1–8.4 的 backport 相容矩陣上執行。getNumPages() 與 setAutoPageBreak() 自 1.0.0 起即為穩定 API。
概念總覽
標題為「概念總覽」的區段一份 NextPDF 文件是一棵頁面樹(page tree)。隨著你加入內容,內部游標(getY())會往下推進。啟用自動分頁後,引擎會在每個內容區塊之前檢查剩餘的垂直空間。如果該區塊放不進底部邊界以上的空間,引擎就會清空目前頁面,並替你呼叫 addPage()。你傳給 setAutoPageBreak() 的底部邊界,就是觸發門檻。
頁面層級的屬性(例如 media box)是可繼承的。ISO 32000-2 §7.7.3.4 規定,頁物件中省略的屬性會從上層的頁面樹節點 resolve(解析)取得。NextPDF 在整份文件套用一致的頁面尺寸,因此每一頁產生時都共用相同的幾何設定,你不必逐頁重複設定。
API 介面
標題為「API 介面」的區段API 介面由 PHPDoc 自動產生。本範例會使用下列方法:
Document::createStandalone(): self— 建立一份獨立文件。setAutoPageBreak(bool $enabled, float $margin = 20): static— 啟用自動分頁。$margin是以毫米為單位的底部邊界觸發值。addPage(?PageSize $size = null, Orientation $orientation = Orientation::Portrait): static— 起始第一頁,以及任何明確新增的頁面。multiCell(...): static/cell(...): static— 輸出可流動或固定的文字區塊。分頁檢查會量測這些區塊。getNumPages(): int— 排版後的頁數。
程式碼範例 — 快速上手
標題為「程式碼範例 — 快速上手」的區段<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setAutoPageBreak(true, margin: 25);$doc->addPage();
$doc->setFont('helvetica', '', 11);for ($i = 1; $i <= 60; $i++) { $doc->multiCell(0, 7, "Line {$i}: content flows until the page is full, " . 'then the engine starts a new page automatically.');}
$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/multi-page.pdf');echo 'Pages: ' . $doc->getNumPages() . "\n";程式碼範例 — 正式環境
標題為「程式碼範例 — 正式環境」的區段這是完整、可直接搭配 harness(測試載具)執行的範例。它會遵循 harness 所設定的 NEXTPDF_COOKBOOK_OUTPUT,因此不要把 PDF 印到 STDOUT。它本身不固定任何亂源(entropy)。當 harness 執行它時,DeterministicMode 會固定時鐘、/ID 與品牌資訊。
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('Multi-Page Document');
// Enable automatic page breaks. The 25 mm bottom margin is the trigger:// when the cursor would cross it, the engine flushes the page and adds// a new one before the next block is drawn.$doc->setAutoPageBreak(true, margin: 25);$doc->addPage();
$doc->setFont('helvetica', 'B', 18);$doc->cell(0, 12, 'Multi-Page Document Example', newLine: true);$doc->ln(5);
for ($chapter = 1; $chapter <= 3; $chapter++) { $doc->setFont('helvetica', 'B', 14); $doc->cell(0, 10, "Chapter {$chapter}: Lorem Ipsum", newLine: true); $doc->setFont('helvetica', '', 11);
for ($para = 1; $para <= 5; $para++) { $text = "Paragraph {$para} of Chapter {$chapter}. " . 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ' . 'Sed do eiusmod tempor incididunt ut labore et dolore magna ' . 'aliqua. Ut enim ad minim veniam, quis nostrud exercitation ' . 'ullamco laboris nisi ut aliquip ex ea commodo consequat.'; $doc->multiCell(0, 7, $text); $doc->ln(3); } $doc->ln(5);}
// The harness sets NEXTPDF_COOKBOOK_OUTPUT; honour it. STDOUT stays free// for progress text only.$out = getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/multi-page.pdf';$doc->save($out);
echo 'Created multi-page.pdf with ' . $doc->getNumPages() . " pages\n";邊界案例與陷阱
標題為「邊界案例與陷阱」的區段- 停用自動分頁。 使用
setAutoPageBreak(false, …)時,超過底部邊界的內容會被裁切在該頁上,不會繼續流動,文件也會維持單一頁。若內容需要流動,請啟用自動分頁。 - 單一區塊高過整頁。 引擎會在內部把超過可列印高度的
multiCell文字拆開。但若是單一區塊高過可用區域且不可分割(例如一張高大的影像),就只會放置一次並溢出。這時請自行手動分頁。 - 第一次的
addPage()仍是必要的。 當尚無任何頁面時,cell()會視需要呼叫addPage()。即便如此,仍請明確呼叫addPage(),讓第一頁的尺寸與方向具有確定性。 - 邊界單位。 在預設單位系統下,
setAutoPageBreak()的邊界是以毫米為單位,而不是以點(point)為單位。
getNumPages() 是 O(1) 操作。它只讀取一個計數器,不會重新進行版面排版。記憶體用量隨保留的內容量而成長,而非隨頁數成長。引擎會在每一頁完成時,就把已完成的頁面寫入輸出緩衝區並清空暫存狀態 — 這就是單趟(single-pass)串流模型(ADR-001)。2000 ms / 64 MB 的預算,足以在參考主機上處理數百頁文字文件。
安全性說明
標題為「安全性說明」的區段本範例只會寫入你的程式碼所提供的文字。它不會進行任何輸入剖析、網路存取或反序列化。請把任何來自外部來源的文字視為不受信任,並在繪製之前先限制其長度。引擎不會替你強制套用應用層級的內容大小上限。
符合性
標題為「符合性」的區段| 陳述 | 規範 | 條款 | 參考 ID |
|---|---|---|---|
一頁的 Contents 是單一串流,或一個依序串接的串流陣列。 | ISO 32000-2 | §7.7.3.3 | |
| 頁物件中省略的可繼承頁面屬性,會從上層的頁面樹節點解析取得。 | ISO 32000-2 | §7.7.3.4 | |
trailer 的 /ID 是由兩個位元組字串組成的檔案識別碼(在 PDF 2.0 中為必填)。 | ISO 32000-2 | §7.5.5 |
可重現性設定檔 — 結構層級(為何不是逐位元組)。 每一份儲存的文件都帶有一個 trailer /ID,其兩個位元組字串即為檔案識別碼(ISO 32000-2 §7.5.5,如上)。第二個元素並非執行間穩定,因此即使內容完全相同,每次執行的原始位元組仍會不同。harness 會比對經 qpdf 正規化後的結構,該流程會剝除 /ID、/CreationDate 與 /ModDate。本範例描述的是 NextPDF 如何產生這個結構。它並未概括性地宣稱符合 ISO 32000-2。
商業情境
標題為「商業情境」的區段不適用。具備自動分頁的多頁排版屬於 Core 能力,沒有 Premium 的限制門檻。