Periksa kotak tata letak sebelum menempatkan konten
Sekilas pandang
Bagian berjudul “Sekilas pandang”Baca geometri tata letak dokumen secara langsung sebelum Anda menempatkan konten. Resep ini membaca kotak halaman, margin, area tanpa-tulis, dan kursor saat ini. Setelah itu, logika penempatan Anda dapat menggunakan angka sebenarnya, bukan koordinat tebakan. Resep ini didukung oleh examples/34-inspect-layout-boxes.php dan harness tests/Cookbook/Php/InspectLayoutBoxesRecipeTest.php-nya.
Pemasangan
Bagian berjudul “Pemasangan”composer require nextpdf/core:^3Anda tidak memerlukan paket Pro atau Enterprise. Permukaan kueri tata letak merupakan bagian dari Core dan berjalan di PHP 8.1 hingga 8.4.
Tinjauan konseptual
Bagian berjudul “Tinjauan konseptual”Halaman Portable Document Format (PDF) memiliki kotak batas. Kotak minimumnya adalah MediaBox, yaitu persegi panjang yang mendefinisikan rentang halaman (ISO 32000-2 §7.7.3.3). Konten diposisikan dalam ruang pengguna. Secara default, ruang pengguna dimulai di sudut kiri bawah, dan satu unit sama dengan 1/72 inci (§8.3.2). NextPDF memberi Anda tampilan kiri-atas yang ramah bagi penulis dan mengekspos geometri melalui metode kueri yang bersifat hanya-baca:
getPageWidth()/getPageHeight()— dimensi kotak halaman.getMargins()— objek nilaiMarginyang aktif (atas/kanan/bawah/kiri).getPageRegions()— zona tanpa-tulis yang dideklarasikan (PageRegion[]). Masing-masing adalah persegi panjang yang tidak dapat diubah dan tempat konten tidak boleh ditempatkan.getX()/getY()— kursor saat ini dalam ruang penulis.
Ini adalah pembacaan idempoten. Metode-metode ini tidak menghasilkan konten, memajukan kursor, atau mengubah state. Gunakan metode-metode ini untuk menghitung ruang vertikal yang tersisa, lalu putuskan apakah akan terus menulis atau memanggil addPage(). Anda juga dapat memposisikan blok relatif terhadap area tanpa-tulis, bukan menggunakan offset yang ditulis langsung di kode.
Permukaan API
Bagian berjudul “Permukaan API”Permukaan API dihasilkan dari PHPDoc. Titik masuk utama berada di trait \NextPDF\Core\Concerns\HasPages dan HasLayout:
Document::getPageWidth(): float/Document::getPageHeight(): floatDocument::getMargins(): \NextPDF\ValueObjects\MarginDocument::getPageRegions(): array(list<\NextPDF\Layout\PageRegion>)Document::addPageRegion(float $x, float $y, float $w, float $h): staticDocument::getX(): float/Document::getY(): float
Contoh kode — Mulai cepat
Bagian berjudul “Contoh kode — Mulai cepat”<?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);Contoh kode — Produksi
Bagian berjudul “Contoh kode — Produksi”Program mandiri ini dijalankan oleh harness. Program ini mencerminkan examples/34-inspect-layout-boxes.php. Program ini membaca geometri halaman, mendeklarasikan area tanpa-tulis footer, dan membuat keputusan berbasis data untuk setiap blok. Jika blok berikutnya akan bertabrakan dengan suatu area atau melampaui margin bawah, program ini menambahkan halaman, bukan mencetak konten yang saling bertumpuk.
<?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);Berikut keluaran standar (STDOUT) yang diharapkan. Angka-angka kotak halaman mencerminkan ukuran halaman A4 baku, dan kursor dimulai pada titik asal konten kiri-atas:
Page box: 595.28 x 841.89 ptCursor start: (<x>, <y>)Pages used: 2 (page breaks decided from layout geometry)Kasus tepi & jebakan
Bagian berjudul “Kasus tepi & jebakan”- Membaca sebelum halaman ada.
getPageWidth()dangetPageHeight()mencerminkan halaman saat ini, jadi panggil keduanya setelahaddPage(). Sebelum halaman pertama, keduanya mengembalikan geometri ukuran halaman baku, bukan geometri halaman yang belum Anda tambahkan. - Area adalah persegi panjang ruang penulis. Nilai
PageRegionyadalah jarak penulis dari kiri-atas, konsisten dengangetY(). Jangan mencampurnya dengan koordinat PDF kiri-bawah mentah. - Pembacaan bebas efek samping. Tidak satu pun metode kueri yang memajukan kursor atau menghasilkan konten. Memanggilnya dalam perulangan ketat aman dan hanya menimbulkan biaya kecil.
- Margin dapat berubah per halaman. Jika halaman berikutnya menetapkan margin yang berbeda, baca ulang
getMargins()alih-alih menyimpan nilai pertama dalam cache. - Area tidak mengalirkan ulang teks secara otomatis. Area tanpa-tulis adalah batasan yang harus Anda patuhi, bukan batas pembungkus teks otomatis. Resep ini memperlihatkan pemeriksaan tabrakan yang eksplisit. Untuk penulisan dengan posisi bebas, mesin tidak pernah memindahkan konten keluar dari suatu area secara otomatis.
Kinerja
Bagian berjudul “Kinerja”Setiap metode di sini adalah pembacaan properti. Metode ini berjalan dalam waktu konstan, tanpa alokasi, serta tanpa input atau output. Contoh ini membangun dokumen multi-halaman kecil yang jauh di bawah anggaran 1500 ms / 96 MB. Profil reproduktibilitasnya bersifat semantik, karena PDF yang dihasilkan membawa trailer /ID dan metadata pembuatan. Bagian terpenting adalah keputusan geometri contoh yang dapat diamati, sehingga harness memvalidasi keputusan tersebut melalui abstract syntax tree (AST) struktural ditambah perbandingan metadata, bukan hash byte.
Catatan keamanan
Bagian berjudul “Catatan keamanan”- Residensi Data & Mitigasi PII. Tidak berlaku. Resep ini membaca geometri dan menata teks yang disediakan oleh pemanggil, sehingga tidak memperkenalkan jalur data baru. Terapkan minimalisasi yang sama pada teks yang Anda tempatkan seperti di bagian lain.
- Telemetri Aman & Pembersihan Log. Contoh ini mencetak angka geometri dan baris kemajuan yang tetap. Contoh ini tidak mencatat teks dokumen.
- Model ancaman. Tidak berlaku. Permukaan kueri bersifat hanya-baca dan tidak mengurai input eksternal apa pun. Ini bukan batas kepercayaan.
- Perilaku mode FIPS. Tidak berlaku. Tidak ada operasi kriptografis yang berjalan.
Kesesuaian
Bagian berjudul “Kesesuaian”| Pernyataan | Spesifikasi | Klausa | reference_id |
|---|---|---|---|
| Objek halaman mendefinisikan rentangnya melalui kotak batas (MediaBox). | ISO 32000-2 | §7.7.3.3 | |
| Persegi panjang halaman adalah batas konten. | ISO 32000-2 | §7.7.3.3 | |
| Posisi diukur dalam ruang pengguna; satu unit adalah 1/72 inci. | ISO 32000-2 | §8.3.2 |
Resep ini membaca geometri yang didefinisikan oleh klausa kotak halaman dan ruang pengguna ISO 32000-2 yang dikutip. Resep ini tidak menyatakan kesesuaian ISO 32000-2 secara menyeluruh. Permukaan kueri tata letak bergantung pada klausa yang dikutip.