コンテンツにスキップ

コンテンツを配置する前にレイアウトボックスを確認する

コンテンツを配置する前に、ドキュメントの現在のレイアウトジオメトリを読み取ります。このレシピでは、ページボックス、マージン、書き込み禁止領域、現在のカーソルを照会します。これにより、配置ロジックは推測した座標ではなく、実際の数値に基づいて動作します。このレシピは examples/34-inspect-layout-boxes.php と、その tests/Cookbook/Php/InspectLayoutBoxesRecipeTest.php ハーネスで検証されています。

Terminal window
composer require nextpdf/core:^3

Pro パッケージや Enterprise パッケージは必要ありません。レイアウト照会 API は Core の一部であり、PHP 8.1 から 8.4 で動作します。

PDF ページには境界ボックスがあります。最小構成では MediaBox があり、これはページ範囲を定義する矩形です(ISO 32000-2 §7.7.3.3)。コンテンツはユーザー空間に配置されます。デフォルトでは、ユーザー空間の原点は左下隅で、1 単位は 1/72 インチに相当します(§8.3.2)。NextPDF は、作成者にとって扱いやすい左上基準のビューを提供し、読み取り専用の照会メソッドでジオメトリを公開します。

  • getPageWidth() / getPageHeight() — ページボックスの寸法。
  • getMargins() — 現在有効な Margin 値オブジェクト(top/right/bottom/left)。
  • getPageRegions() — 宣言済みの書き込み禁止ゾーン(PageRegion[])。それぞれは、コンテンツ配置が禁止された不変の矩形です。
  • getX() / getY() — 作成者空間における現在のカーソル。

これらは 冪等な読み取り です。コンテンツを出力したり、カーソルを進めたり、状態を変更したりすることはありません。残りの垂直スペースを計算し、書き込みを続けるか addPage() を呼び出すかの判断に使用します。また、ハードコードしたオフセットではなく、書き込み禁止領域を基準にブロックを配置する用途にも使えます。

API サーフェスは PHPDoc から生成されます。主なエントリポイントは、\NextPDF\Core\Concerns\HasPages および HasLayout トレイトにあります。

  • Document::getPageWidth(): float / Document::getPageHeight(): float
  • Document::getMargins(): \NextPDF\ValueObjects\Margin
  • Document::getPageRegions(): array (list<\NextPDF\Layout\PageRegion>)
  • Document::addPageRegion(float $x, float $y, float $w, float $h): static
  • Document::getX(): float / Document::getY(): float
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->addPage();
$pageHeight = $doc->getPageHeight();
$margins = $doc->getMargins();
$cursorY = $doc->getY();
// Vertical space left before the bottom margin.
$remaining = $pageHeight - $margins->bottom - $cursorY;
// Geometry is in user-space units (PDF points; 1 pt = 1/72 in).
echo sprintf("Page height: %.2f pt\n", $pageHeight);
echo sprintf("Bottom margin: %.2f pt\n", $margins->bottom);
echo sprintf("Cursor Y: %.2f pt\n", $cursorY);
echo sprintf("Remaining: %.2f pt\n", $remaining);

これは自己完結型で、ハーネスから実行できるプログラムです。examples/34-inspect-layout-boxes.php を反映しています。このプログラムはページのジオメトリを読み取り、フッターの書き込み禁止領域を宣言し、ブロックごとにデータに基づいて判断します。次のブロックが領域と衝突するか下マージンを超える場合は、上書きせずにページを追加します。

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Layout Box Inspection Demo');
$doc->setLanguage('en');
$doc->addPage();
// Read the geometry (idempotent, no side effects). Values are in
// user-space units (PDF points; 1 pt = 1/72 in).
$pageWidth = $doc->getPageWidth();
$pageHeight = $doc->getPageHeight();
$margins = $doc->getMargins();
echo sprintf("Page box: %.2f x %.2f pt\n", $pageWidth, $pageHeight);
echo sprintf("Cursor start: (%.2f, %.2f)\n", $doc->getX(), $doc->getY());
// A 15 pt tall footer no-write zone across the text column.
$footerHeight = 15.0;
$footerTop = $pageHeight - $margins->bottom - $footerHeight;
$doc->addPageRegion(
$margins->left,
$footerTop,
$pageWidth - $margins->left - $margins->right,
$footerHeight,
);
$blocks = [
'Section 1. Each block measures the live cursor against the page box '
. 'and any no-write region before it is placed.',
'Section 2. The lowest Y at which any region starts is the hard floor '
. 'for new content; crossing it forces a page break.',
'Section 3. Reading geometry is idempotent — the query methods never '
. 'advance the cursor, so they are safe in the placement loop.',
'Section 4. This final block forces a second page when the column is '
. 'already near the footer keep-out zone.',
];
$blockHeight = 42.0;
$pagesUsed = 1;
foreach ($blocks as $index => $text) {
$cursorY = $doc->getY();
// Lowest Y a region starts at — the hard floor for new content.
$regionFloor = $pageHeight - $margins->bottom;
foreach ($doc->getPageRegions() as $region) {
$regionFloor = min($regionFloor, $region->y);
}
if ($cursorY + $blockHeight > $regionFloor) {
$doc->addPage();
++$pagesUsed;
// A fresh page resets the region set; re-declare the footer zone.
$footerTop = $doc->getPageHeight() - $doc->getMargins()->bottom - $footerHeight;
$doc->addPageRegion(
$doc->getMargins()->left,
$footerTop,
$doc->getPageWidth() - $doc->getMargins()->left - $doc->getMargins()->right,
$footerHeight,
);
}
$doc->setFont('helvetica', 'B', 12);
$doc->cell(0, 8, 'Block ' . ($index + 1), newLine: true);
$doc->setFont('helvetica', '', 11);
$doc->multiCell(0, 7, $text);
$doc->ln(6);
}
// The harness sets NEXTPDF_COOKBOOK_OUTPUT and runs this script under the
// semantic profile (validated by structural AST + metadata, not a byte hash).
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');
$doc->save($out !== false && $out !== '' ? $out : __DIR__ . '/inspect-layout-boxes.pdf');
echo sprintf("Pages used: %d (page breaks decided from layout geometry)\n", $pagesUsed);

想定される STDOUT は次のとおりです。ページボックスの数値はデフォルトの A4 ページサイズを反映しており、カーソルは左上のコンテンツ原点から始まります。

Page box: 595.28 x 841.89 pt
Cursor start: (<x>, <y>)
Pages used: 2 (page breaks decided from layout geometry)
  • ページが存在する前に読み取る。 getPageWidth()getPageHeight()現在の ページを反映するため、addPage() の後に呼び出してください。最初のページを追加する前は、これらのメソッドは未追加のページではなく、デフォルトページサイズのジオメトリを返します。
  • 領域は作成者空間の矩形です。 PageRegiony は左上を基準にした作成者距離であり、getY() と一致します。左下基準の生の PDF 座標と混在させないでください。
  • 読み取りには副作用がありません。 いずれの照会メソッドも、カーソルを進めたりコンテンツを出力したりしません。タイトなループ内で呼び出しても安全で、コストもほとんどかかりません。
  • マージンはページごとに変わる場合があります。 後続のページが異なるマージンを設定する場合は、最初の値をキャッシュせずに getMargins() を再度読み取ってください。
  • 領域はテキストを自動的に再フローしません。 書き込み禁止領域は 守らなければならない制約 であり、自動的なテキスト折り返しの境界ではありません。このレシピでは明示的な衝突チェックを示しています。自由配置で書き込む場合、エンジンが独自にコンテンツを領域外へ移動することはありません。

ここで紹介するメソッドはいずれもプロパティ読み取りです。割り当ても入出力もなく、一定時間で実行されます。この例では、小さな複数ページドキュメントを 1500 ms / 96 MB の予算内に十分収まる形で構築します。再現性プロファイルは セマンティック です。これは、生成された PDF がトレーラーの /ID と作成メタデータを保持するためです。この例で重要なのは観測可能なジオメトリ判断であるため、ハーネスはバイトハッシュではなく、構造的な抽象構文木(AST)とメタデータの比較を通じて、その判断を検証します。

  • データレジデンシーと PII の緩和策。 該当しません。このレシピはジオメトリを読み取り、呼び出し元が提供したテキストを配置するだけなので、新たなデータ経路は導入しません。配置するテキストには、他の箇所と同様にデータ最小化を適用してください。
  • 安全なテレメトリとログのスクラビング。 この例はジオメトリの数値と固定の進捗行を出力します。ドキュメント内のテキストはログに記録しません。
  • 脅威モデル。 該当しません。照会 API は読み取り専用であり、外部入力を解析しません。これは信頼境界ではありません。
  • FIPS モードの動作。 該当しません。暗号化処理は実行されません。
記述仕様箇条reference_id
ページオブジェクトの範囲を定義する境界ボックス(MediaBox)ISO 32000-2§7.7.3.3
コンテンツの境界としてのページ矩形ISO 32000-2§7.7.3.3
ユーザー空間で測定される位置と、1 単位が 1/72 インチである尺度ISO 32000-2§8.3.2

このレシピは、引用された ISO 32000-2 のページボックスおよびユーザー空間に関する箇条が定義するジオメトリを読み取ります。ISO 32000-2 への全面的な準拠を主張するものではありません。引用された箇条は、レイアウト照会 API が依拠する根拠です。