跳到內容
getnextpdf.com

頁首、頁尾與多頁文件

一頁通常不夠用。在本教學中,您會撰寫一份自行擴展到三頁的文件。您也會為每一頁加上會重複出現的頁首,以及顯示頁碼的頁尾。

您將撰寫一支腳本 01-multipage.php。它會產生一份三頁的旅行日誌,並儲存為 PDF(Portable Document Format)檔案:

  • 日誌的條目會自動從一頁流動到下一頁。您完全不必指定一頁在哪裡結束;由引擎來決定。
  • 頁首是位於頁面頂端、會在每一頁重複出現的橫條。您的頁首會顯示文件標題。
  • 頁尾則是位於底部的對應橫條。您的頁尾會以 1 / 32 / 33 / 3 的形式顯示頁碼。

一切只需 nextpdf/core 這一個套件即可執行:不需要字型檔案、不需要額外的擴充功能,也不需要網路。

這支腳本靠兩個概念完成所有工作。

第一個是自動換頁。當引擎寫入文字時,它會追蹤一個游標:頁面上下一行文字將要落腳的位置。setAutoPageBreak(true, margin: 25) 會告訴引擎去留意那個游標。當它接近底部邊緣、距離不到 25 點(約三分之一英吋)時,引擎便會結束目前這一頁,並開始新的一頁。

第二個則是頁面上的固定元素:頁首與頁尾。您只需在第一頁之前描述它們一次。setHeaderData() 會為頂端的橫條記錄標題與一段簡短的說明。字型與邊距的呼叫則決定字體樣式,以及與頁面邊緣的距離。接著,引擎會在它建立的每一頁上繪製這些固定元素,包括它自行新增的頁面。

在您的專案資料夾中建立 01-multipage.php

<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
// Make sure the output folder exists next to this script.
@mkdir(__DIR__ . '/out');
$document = Document::createStandalone();
$document->setTitle('NextPDF Travel Journal');
// Configure the header and footer BEFORE the first page.
// The engine repeats them on every page for you.
$document->setHeaderData(title: 'NextPDF Travel Journal', description: 'A multi-page tutorial document');
$document->setHeaderFont('helvetica', 10);
$document->setHeaderMargin(5);
$document->setFooterFont('helvetica', 8);
$document->setFooterMargin(10);
// Turn on automatic page breaks. When the text cursor gets within
// 25 points of the bottom edge, the engine starts a new page.
$document->setAutoPageBreak(true, margin: 25);
$document->addPage();
$document->setFont('helvetica', 'B', 18);
$document->cell(0, 12, 'Travel journal: three days on the coast', newLine: true);
$document->ln(5);
$days = [
1 => 'We followed the shoreline north and counted seventeen lighthouses.',
2 => 'Rain moved in before noon, so we sketched the harbor from a cafe window.',
3 => 'On the last morning the fog lifted and the whole bay turned silver.',
];
foreach ($days as $day => $highlight) {
$document->setFont('helvetica', 'B', 14);
$document->cell(0, 10, "Day {$day}", newLine: true);
$document->setFont('helvetica', '', 11);
for ($entry = 1; $entry <= 12; $entry++) {
$text = "Entry {$entry} of day {$day}. {$highlight} "
. 'The trail hugged the cliffs for most of the afternoon, and every '
. 'turn opened another view of the water. We stopped often to take '
. 'notes, compare maps, and argue happily about where to eat dinner. '
. 'By the time we reached the guesthouse, our boots were soaked and '
. 'our notebooks were full.';
$document->multiCell(0, 7, $text);
$document->ln(3);
}
$document->ln(5);
}
// Ask the engine how many pages the layout produced, then save.
$pages = $document->getNumPages();
$document->save(__DIR__ . '/out/travel-journal.pdf');
echo "Wrote out/travel-journal.pdf with {$pages} pages\n";

使用 php 01-multipage.php 執行它。這支腳本會印出一行:

Wrote out/travel-journal.pdf with 3 pages

開啟 out/travel-journal.pdf 並上下捲動瀏覽。標題橫條位於全部三頁的頂端,頁碼則在右下角依序遞增。

這段寫入迴圈從未提及頁面。它以 cell() 寫出每一天的標題,把一行文字放進一個看不見的方框裡。它以 multiCell() 寫出各個條目,將長文字依需要換行成任意多行。三十六則條目無法容納在一頁上,因此自動換頁觸發了兩次。日誌就是這樣剛好變成三頁的。

頁首與頁尾是在第一次呼叫 addPage() 之前設定的。這個順序很重要:頁面一旦繪製完成,之後就不會再更新。先設定好這些固定元素,每一頁的呈現才會一致。

您從未親自繪製頁碼。頁尾預設就會印出它;您只選擇了它的字型,以及它與頁面邊緣的距離。當引擎正在寫入各頁時,它還無法得知最終的頁數。因此它會在每個頁尾留下一個預留位置,並在您儲存時填入真正的總頁數。

還有兩個小細節讓這支腳本更為完整。@mkdir 會建立 out 資料夾,而 @ 符號會在資料夾已存在時讓 PHP 保持安靜。getNumPages() 會詢問引擎這份版面配置產生了多少頁,讓最後的訊息能夠回報真正的頁數。

  • require 那一行出現「failed to open stream」錯誤,代表腳本找不到 vendor/autoload.php。請在包含 vendor/ 的專案資料夾內執行它。
  • 所有內容都擠在同一頁上,而且文字的結尾被截掉了?那麼自動換頁是關閉的。請保留 setAutoPageBreak(true, margin: 25) 這一行,並讓它位於寫入迴圈之前。
  • 拼錯的字型系列會拋出一個例外,並指出它找不到的字型。請檢查 helvetica 的拼字,並參閱字型與標記以了解更深入的字型問題。
  • 至於其他任何情況,疑難排解中心會將症狀對應到成因,而錯誤參考則會說明引擎的一般例外,以及如何從每一種例外中復原。

您的文件現在可以增長到任意長度,看起來卻依然完整。在 下一個教學中,您會用 HTML(Hypertext Markup Language)撰寫內容,並讓引擎把它轉換成頁面。

當您想對今天的主題有更細緻的掌控時,有兩篇食譜會談得更深入: