レイアウト: ヘッダー、フッター、段組み、小冊子、ページマネージャー
Layout モジュールには、Document ファサードが処理を委譲するページ装飾エンジンが含まれます。ヘッダーとフッターのレンダリング、段組みレイアウト、中綴じ小冊子の面付け、構造的なページ操作を担います。これは小規模で安定したモジュールであり、6 つのクラスはすべて@since 1.0.0です。
インストール
「インストール」という見出しのセクションcomposer require nextpdf/core:^3概念の概要
「概念の概要」という見出しのセクションLayout(src/Layout/、6 つのクラス、@since 1.0.0)は、HasLayout トレイトの基盤となるエンジン層です。アプリケーションコードはDocument のファサードメソッドを呼び出し、トレイトが各呼び出しをこれらのエンジンのいずれかに振り分けます。このモジュールはマニフェストでstandard リスク、internal 安定性としてマークされており、依存先はCore のみです。クラスを直接構築せず、ファサードを通じてアクセスします。
HeaderFooter は、繰り返し表示されるヘッダーとフッターをレンダリングします。各バンドのタイトル、説明、ロゴ、フォント、マージン、色の状態を保持します。PDF コンテンツストリームのオペレーターはrenderHeader() とrenderFooter() が生成します。デフォルトのフッターは、右揃えの"page / total" 文字列を出力します。setHeaderCallback() とsetFooterCallback() は、デフォルトのレイアウトを呼び出し元が指定したクロージャーに置き換えます。getHeaderContentHeight() は、ヘッダーが消費する垂直方向のスペースを返し、ページ本文がその下から開始できるようにします。ドキュメントがタグ付き PDF モードの場合、ヘッダーのコンテンツは構造ツリーの外側に位置するため、自動ヘッダーは上流のHasPages で抑制されます。
ColumnLayout は段組みのフローを管理します。setEqualColumns(int $count, float $totalWidth, float $gap = 5) は、利用可能な幅を等しい段に分割します。setColumnsArray() は、明示的なColumnDefinition の位置と幅を受け取ります。カーソルはselectColumn() で段を選択するか、nextColumn() で次の段へ進めます。getCurrentColumnX()/getCurrentColumnWidth() は、アクティブな段のジオメトリを返します。不正な段数、負のギャップ、または計算された段幅が正でない場合は、PageLayoutException が発生します。
BookletLayout は、中綴じ(センターフォールド)製本のためにページを並べ替えます。reorderPages() は、ページリストを 4 の倍数にパディングし(1 枚の小冊子用紙には 4 つのページスロットがあります)、折ってステープルで綴じた用紙が順番に読めるよう、ページを外側から内側へ面付けします。getMarginAdjustments() は、指定された位置について、各辺の内側(背)と外側(端)のマージンを返します。getSheetCount() は、指定されたページ数に必要な両面用紙の枚数を返します。並べ替えはコンテンツの配置のみを変更します。基盤となる PDF のページシーケンスは線形のまま保たれ、ドキュメント内のページの順序を定義するページツリーと整合します(ISO 32000-2§7.7)。
PageManager は、コンテンツのレンダリングとは別に、構造的なページ操作を提供します。movePage()、copyPage()、deletePage() は、PageData 配列を参照渡しで操作します。ページ領域(addPageRegion()、isInRegion()、getRegionOffset())は、書き込み禁止ゾーンを定義します。ページグループ(startPageGroup()、getGroupPageNo())は、セクションごとのページ番号付けをサポートします。PageRegion とColumnDefinition は、これらのエンジンが使用する 2 つの値キャリアです。Writer モジュールは、結果として得られたページを、Kids エントリがページツリーノードの直接の子への間接参照の配列となるページツリーへシリアライズします(ISO 32000-2§7.7.3.2)。
API サーフェス
「API サーフェス」という見出しのセクション| シンボル | 種別 | 安定性 | 導入バージョン |
|---|---|---|---|
HeaderFooter::setHeaderData(string, string, string, float): self | メソッド | stable | 1.0.0 |
HeaderFooter::setHeaderFont(string, float): self/setHeaderMargin(float): self | メソッド | stable | 1.0.0 |
HeaderFooter::setFooterFont(string, float): self/setFooterMargin(float): self | メソッド | stable | 1.0.0 |
HeaderFooter::setHeaderCallback(Closure): self/setFooterCallback(Closure): self | メソッド | stable | 1.0.0 |
HeaderFooter::getHeaderContentHeight(): float | メソッド | stable | 1.0.0 |
HeaderFooter::renderHeader(float, float, float, float, int, int): string | メソッド | stable | 1.0.0 |
HeaderFooter::renderFooter(float, float, float, float, int, int, string): string | メソッド | stable | 1.0.0 |
ColumnLayout::setEqualColumns(int, float, float): self | メソッド | stable | 1.0.0 |
ColumnLayout::setColumnsArray(array): self/resetColumns(): self | メソッド | stable | 1.0.0 |
ColumnLayout::selectColumn(int): self/nextColumn(): bool | メソッド | stable | 1.0.0 |
ColumnLayout::getCurrentColumnX(float): float/getCurrentColumnWidth(float): float | メソッド | stable | 1.0.0 |
BookletLayout::setBooklet(bool, float, float): void | メソッド | stable | 1.0.0 |
BookletLayout::reorderPages(array): array | メソッド | stable | 1.0.0 |
BookletLayout::getMarginAdjustments(int): array{left: float, right: float} | メソッド | stable | 1.0.0 |
BookletLayout::getSheetCount(int): int | メソッド | stable | 1.0.0 |
PageManager::movePage(int, int, array): void/copyPage(int, array): void/deletePage(int, array): void | メソッド | stable | 1.0.0 |
PageManager::addPageRegion(float, float, float, float): void/isInRegion(float, float): bool | メソッド | stable | 1.0.0 |
PageManager::getRegionOffset(float, float, float, float): float | メソッド | stable | 1.0.0 |
PageManager::startPageGroup(): void/getGroupPageNo(int): int | メソッド | stable | 1.0.0 |
PageRegion/ColumnDefinition | 値キャリア | stable | 1.0.0 |
コードサンプル — クイックスタート
「コードサンプル — クイックスタート」という見出しのセクション<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('Header and Footer');
$doc->setHeaderData( title: 'NextPDF Example', description: 'Header and Footer Demonstration',);$doc->setHeaderFont('helvetica', 10);$doc->setHeaderMargin(5);$doc->setFooterFont('helvetica', 8);$doc->setFooterMargin(10);
$doc->addPage();$doc->setFont('helvetica', 'B', 16);$doc->cell(0, 12, 'Document with Header and Footer', newLine: true);
$doc->save(__DIR__ . '/output/13-header-footer.pdf');ソース: examples/13-header-footer.php。ヘッダーはaddPage() ごとにレンダリングされ、フッターはページがフラッシュされるときにレンダリングされます。
コードサンプル — 本番環境
「コードサンプル — 本番環境」という見出しのセクションフッターコールバックがページ番号テキストを管理し、段組みエンジンが 2 段の本文を制御します。どちらのエンジンにもファサードを通じてアクセスします。
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('Two-Column Report');
$doc->setFooterCallback(static function (Document $d): void { $d->setFont('helvetica', '', 8); $d->text(180.0, 285.0, 'Page ' . ($d->getPage() + 1));});
$doc->addPage();$doc->setEqualColumns(2, gap: 8);$doc->selectColumn(0);$doc->setFont('helvetica', '', 10);$doc->multiCell(0, 6, 'Left column flows here.');$doc->selectColumn(1);$doc->multiCell(0, 6, 'Right column flows here.');
$doc->save(__DIR__ . '/output/two-column-report.pdf');ソース: 以下のパターンに基づきます: examples/13-header-footer.php。
エッジケースと注意点
「エッジケースと注意点」という見出しのセクションsetEqualColumns()は、1 未満の段数、負のギャップ、または計算された段幅が正でないレイアウトを拒否します。これらのいずれの場合も、劣化したレイアウトを返すのではなくPageLayoutExceptionを発生させます。selectColumn()は範囲外のインデックスを無視して現在の段を維持し、不正なインデックスで例外をスローすることはありません。nextColumn()は、すでに最後の段にある場合にfalseを返します。BookletLayout::reorderPages()は、最後のページの寸法を複製した空白ページで 4 の倍数にパディングします。空のページリストは空の配列を返します。並べ替えは配置のみに影響します。movePage()のインデックスは引き続き論理的な順序を参照します。PageManager::movePage()、copyPage()、deletePage()は、範囲外のインデックスに対して何も行わずに静かに終了します。これらはisset()で検証し、配列を変更せずに戻ります。ページの欠落が呼び出し元のエラーとなる場合は、インデックスを自分で検証してください。getHeaderContentHeight()は、ヘッダーが無効である場合、またはタイトルと説明のいずれも持たない場合に0.0を返します。その場合、ページ本文は上マージンから開始します。- タグ付き PDF モードでは、自動ヘッダーは上流で抑制されます。アクセシブルなドキュメントのために、構造を意識したレイアウトを構築してください。
パフォーマンス
「パフォーマンス」という見出しのセクションヘッダーとフッターのレンダリングは、O(装飾コンテンツ) でアクティブなページバッファーにオペレーターを追加します。コストは、書き込まれるタイトル、説明、区切り線に比例し、ドキュメントのサイズには比例しません。段組みの計算は、呼び出しごとに O(1) です。BookletLayout::reorderPages() はページ数に対して O(n) であり、1 回限りのパディングパスを伴います。面付けのループは、パディングされた各スロットを 1 回ずつ処理します。PageManager の領域テストは、ポイントごとに O(領域数) です。ページ操作は O(n) の配列スプライスです。これらのエンジンはいずれもドキュメント全体にわたるページ単位の状態を保持しないため、長いドキュメントでのメモリ増加には寄与しません。主要なメモリコストは蓄積されたコンテンツストリームであり、ストリーミングとメモリの概念 で説明しています。HTML パイプラインのレイテンシーとメモリバジェットのゲートはPERFORMANCE-BUDGETS に記載されています。これは HTML レンダリングパスを対象としており、これらのレイアウトエンジンを直接ゲートするものではありません。performance_budget の 1500 ms / 64 MB は、クイックスタートのキャンバスのエンベロープであり、呼び出しごとの契約ではありません。
セキュリティに関する注意
「セキュリティに関する注意」という見出しのセクションこれらのエンジンは、呼び出し元が指定する文字列とロゴパスを使用します。ロゴパスは画像エンジンを経由し、画像エンジンは埋め込み前にファイルを検証します。renderHeader() とrenderFooter() は、タイトル、説明、ページ番号のテキストがコンテンツストリームに到達する前に、一元化された PDF 文字列エスケーパーを通じてエスケープします。これにより、呼び出し元のテキストがリテラル文字列の文法から逸脱することはありません。ヘッダーまたはフッターのコールバックは、ドキュメントの他の部分と同じ信頼レベルで呼び出し元のコードを実行します。そのコードが読み取る外部データは、それに応じて扱ってください。PageManager のページ操作は、既存のPageData への参照を移動するものであり、信頼できないバイト列を解析することはありません。
| 主張 | 規格 | 箇条 | エビデンス |
|---|---|---|---|
| 小冊子出力のためのページ並べ替えは配置のみを変更します。ページツリーは引き続き、ドキュメント内のページの線形順序を定義します。 | ISO 32000-2 | §7.7 | |
シリアライズされたページツリーノードのKids エントリは、そのノードの直接の子への間接参照の配列です。 | ISO 32000-2 | §7.7.3.2 |
箇条は言い換えられ、用語集に固定されています。規範的なテキストは複製されていません。
- Core/HasLayout トレイト — これらのエンジンを構成するファサードトレイトです。
- Core/HasPages トレイト — 段組みの計算が参照するページサイズとマージンです。
- Writer — レイアウト済みのページをシリアライズする PDF オブジェクトおよびページツリーのエミッターです。
- ストリーミングとメモリ — 装飾エンジンがページ単位の状態を保持しない理由と、メモリに依存するレンダリングパスについて。
- HTML / ストリーミング制約 (ADR-001) — シングルパスのストリーミングスコープに関する根拠です。