コンテンツにスキップ
getnextpdf.com

ヘッダー、フッター、複数ページのドキュメント

1 ページで足りることはめったにありません。このチュートリアルでは、自動的に 3 ページへと成長するドキュメントを作成します。さらに、すべてのページに繰り返し表示されるヘッダーと、ページ番号を表示するフッターを追加します。

1 つのスクリプト 01-multipage.php を作成します。これは 3 ページの旅行記を PDF (Portable Document Format) ファイルとして生成します。

  • 旅行記のエントリーは、ページからページへと自動的に流れていきます。ページの終わりを指定することはなく、エンジンが判断します。
  • ヘッダー は、すべてのページで繰り返される、ページ上部の帯です。ここではドキュメントのタイトルを表示します。
  • フッター は、それと対になる下部の帯です。ここではページ番号を 1 / 32 / 33 / 3 のように表示します。

すべては nextpdf/core パッケージだけで動作します。フォントファイルも、追加の拡張機能も、ネットワークも必要ありません。

このスクリプトでは、2 つのアイデアがすべての処理を担います。

1 つ目は 自動改ページ です。エンジンはテキストを書き込みながら、カーソル、つまり次の行が配置されるページ上の位置を追跡します。setAutoPageBreak(true, margin: 25) は、エンジンにそのカーソルを監視するよう指示します。カーソルが下端から 25 ポイント(およそ 3 分の 1 インチ)以内に近づくと、エンジンはそのページを閉じ、新しいページを開始します。

2 つ目は、ページの装飾要素(page furniture)、すなわちヘッダーとフッターです。これらは最初のページの前に一度だけ記述します。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 で実行します。スクリプトは 1 行を出力します。

Wrote out/travel-journal.pdf with 3 pages

out/travel-journal.pdf を開き、スクロールして確認してください。タイトルの帯が 3 ページすべての上部に表示され、ページ番号が右下でカウントアップしていきます。

書き込みループはページについて一切言及していません。各日の見出しは cell() で書き込まれ、これは 1 行を目に見えないボックスに配置します。エントリーは multiCell() で書き込まれ、これは長いテキストを必要なだけの行数に折り返します。36 件のエントリーは 1 ページに収まらないため、自動改ページが 2 回発生します。こうして、旅行記はちょうど 3 ページになります。

ヘッダーとフッターは、最初の addPage() 呼び出しよりも前に設定されました。この順序は重要です。すでに描画されたページは、後から更新されません。装飾要素を先に設定すれば、すべてのページが一貫した仕上がりになります。

ページ番号を自分で描画することはありませんでした。フッターはデフォルトでこれを出力します。選んだのは、そのフォントとページ端からの距離だけです。エンジンがページを書き込んでいる間は、最終的なページ数をまだ知ることができません。そのため、各フッターにプレースホルダーを残しておき、保存時に本当の合計数を埋め込みます。

2 つの小さな詳細がスクリプトを仕上げます。@mkdirout フォルダーを作成し、 @ 記号は、フォルダーがすでに存在する場合に PHP のエラー出力を抑制します。 getNumPages() は、レイアウトが生成したページ数をエンジンに問い合わせるため、最後のメッセージで実際のページ数を報告できます。

  • require の行で「failed to open stream」エラーが出る場合、スクリプトが vendor/autoload.php を見つけられなかったことを意味します。vendor/ を含むプロジェクトフォルダー内で実行してください。
  • すべてが 1 ページに収まってしまい、テキストの末尾が切れていませんか?その場合、自動改ページがオフになっています。setAutoPageBreak(true, margin: 25) の行を残し、それを書き込みループよりも上に配置してください。
  • フォントファミリーのスペルミスは、見つけられなかったフォント名を示す例外をスローします。helvetica のスペルを確認し、より深いフォントの問題については フォントとタグ付け を参照してください。
  • その他の問題については、トラブルシューティングハブ が症状を原因に対応付け、エラーリファレンス がエンジンの一般的な例外と、それぞれからの回復方法を説明します。

これでドキュメントは任意の長さまで成長でき、それでも完成された見た目を保てます。 次のチュートリアル では、コンテンツを HTML (Hypertext Markup Language) で記述し、エンジンにそれをページへと変換させます。

今回のトピックをより細かく制御したい場合は、2 つのレシピがさらに掘り下げています。