ข้ามไปยังเนื้อหา

ตรวจสอบกล่องเค้าโครงก่อนวางเนื้อหา

อ่านเรขาคณิตเค้าโครงปัจจุบันของเอกสารก่อนวางเนื้อหา สูตรนี้อ่านกล่องหน้า ระยะขอบ พื้นที่ห้ามเขียน และตำแหน่งเคอร์เซอร์ปัจจุบัน จากนั้นตรรกะการวางตำแหน่งจะใช้ตัวเลขจริงแทนการคาดเดาพิกัดได้ สูตรนี้มี examples/34-inspect-layout-boxes.php และเฟรมเวิร์กทดสอบ tests/Cookbook/Php/InspectLayoutBoxesRecipeTest.php รองรับ

Terminal window
composer require nextpdf/core:^3

ไม่จำเป็นต้องใช้แพ็กเกจ Pro หรือ Enterprise พื้นผิวสำหรับสอบถามเค้าโครงเป็นส่วนหนึ่งของ Core และทำงานบน PHP 8.1 ถึง 8.4

หน้าของ Portable Document Format (PDF) มีกล่องขอบเขต อย่างน้อยต้องมี MediaBox ซึ่งเป็นสี่เหลี่ยมผืนผ้าที่กำหนดขอบเขตของหน้า (ISO 32000-2 §7.7.3.3) เนื้อหาจะถูกวางตำแหน่งในพื้นที่ผู้ใช้ โดยค่าเริ่มต้น พื้นที่ผู้ใช้เริ่มที่มุมล่างซ้าย และหนึ่งหน่วยเท่ากับ 1/72 นิ้ว (§8.3.2) NextPDF ให้มุมมองจากมุมบนซ้ายที่เป็นมิตรต่อผู้เขียน และเปิดเผยเรขาคณิตผ่านเมธอดการสอบถามแบบอ่านอย่างเดียว:

  • getPageWidth() / getPageHeight() — ขนาดของกล่องหน้า
  • getMargins() — value object ของ Margin ที่ใช้งานอยู่ (บน/ขวา/ล่าง/ซ้าย)
  • getPageRegions() — โซนห้ามเขียนที่ประกาศไว้ (PageRegion[]) แต่ละโซนคือสี่เหลี่ยมผืนผ้าที่ไม่เปลี่ยนแปลงได้และห้ามวางเนื้อหา
  • getX() / getY() — ตำแหน่งเคอร์เซอร์ปัจจุบันในพื้นที่ผู้เขียน

เมธอดเหล่านี้เป็นการอ่านแบบ idempotent คือไม่ปล่อยเนื้อหา ไม่เลื่อนเคอร์เซอร์ และไม่เปลี่ยนสถานะ ใช้เพื่อคำนวณพื้นที่แนวตั้งที่เหลือ จากนั้นตัดสินใจว่าจะเขียนต่อหรือเรียก addPage() คุณยังสามารถจัดวางบล็อกโดยอ้างอิงพื้นที่ห้ามเขียนแทนการใช้ค่าออฟเซ็ตที่ฮาร์ดโค้ดไว้ได้

พื้นผิว application programming interface (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 ที่สร้างขึ้นมี trailer /ID และเมทาดาทาของการสร้าง การตัดสินใจด้านเรขาคณิตที่สังเกตได้ในตัวอย่างเป็นส่วนสำคัญที่สุด ดังนั้นเฟรมเวิร์กทดสอบจึงตรวจสอบการตัดสินใจเหล่านั้นผ่านการเปรียบเทียบ abstract syntax tree (AST) เชิงโครงสร้างร่วมกับเมทาดาทา แทนการใช้ byte hash

  • ถิ่นที่อยู่ของข้อมูลและการลดความเสี่ยง PII ไม่เกี่ยวข้อง สูตรนี้อ่านเรขาคณิตและจัดวางข้อความที่ผู้เรียกจัดเตรียมมา จึงไม่เปิดเส้นทางข้อมูลใหม่ ใช้หลักการลดข้อมูลให้น้อยที่สุดกับข้อความที่คุณวางเช่นเดียวกับส่วนอื่น
  • เทเลเมทรีที่ปลอดภัยและการชำระล้างบันทึก ตัวอย่างพิมพ์ตัวเลขเรขาคณิตและบรรทัดแสดงความคืบหน้าแบบตายตัว โดยไม่บันทึกข้อความของเอกสาร
  • แบบจำลองภัยคุกคาม ไม่เกี่ยวข้อง พื้นผิวการสอบถามเป็นแบบอ่านอย่างเดียวและไม่แยกวิเคราะห์อินพุตภายนอก พื้นผิวนี้ไม่ใช่ขอบเขตความเชื่อถือ
  • พฤติกรรมในโหมด FIPS ไม่เกี่ยวข้อง ไม่มีการดำเนินการเข้ารหัสลับใดทำงาน
ข้อความข้อกำหนดข้อรหัสอ้างอิง (reference_id)
อ็อบเจกต์หน้ากำหนดขอบเขตของตนผ่านกล่องขอบเขต (MediaBox)ISO 32000-2§7.7.3.3
สี่เหลี่ยมผืนผ้าของหน้าคือขอบเขตเนื้อหาISO 32000-2§7.7.3.3
ตำแหน่งวัดในพื้นที่ผู้ใช้ หนึ่งหน่วยคือ 1/72 นิ้วISO 32000-2§8.3.2

สูตรนี้อ่านเรขาคณิตตามข้อกำหนดเรื่องกล่องหน้าและพื้นที่ผู้ใช้ของ ISO 32000-2 ที่อ้างถึง สูตรนี้ไม่อ้างความสอดคล้องกับ ISO 32000-2 แบบครอบคลุมทั้งหมด พื้นผิวการสอบถามเค้าโครงอาศัยข้อที่อ้างถึง