Ga naar inhoud

Inspecteer lay-outvakken voordat u inhoud plaatst

Lees de huidige lay-outgeometrie van een document uit voordat u inhoud plaatst. Dit recipe leest het paginavak, de marges, de niet-beschrijfbare gebieden en de huidige cursor uit. Uw plaatsingslogica kan daarna werken met werkelijke getallen in plaats van geschatte coördinaten. Het recipe wordt gedekt door examples/34-inspect-layout-boxes.php en het bijbehorende tests/Cookbook/Php/InspectLayoutBoxesRecipeTest.php-testharnas.

Terminal window
composer require nextpdf/core:^3

U hebt geen Pro- of Enterprise-pakket nodig. Het lay-outquery-oppervlak maakt deel uit van Core en draait op PHP 8.1 tot en met 8.4.

Een pagina in Portable Document Format (PDF) heeft begrenzingsvakken. Minimaal is er de MediaBox, de rechthoek die de paginaomvang definieert (ISO 32000-2 §7.7.3.3). Inhoud wordt gepositioneerd in de gebruikersruimte. Standaard begint de gebruikersruimte linksonder en is één eenheid gelijk aan 1/72 inch (§8.3.2). NextPDF biedt u een auteursvriendelijke weergave vanuit linksboven en stelt de geometrie beschikbaar via querymethoden die alleen lezen:

  • getPageWidth() / getPageHeight() — afmetingen van het paginavak.
  • getMargins() — het actieve Margin-waardeobject (boven/rechts/onder/links).
  • getPageRegions() — de gedeclareerde niet-beschrijfbare zones (PageRegion[]). Elke zone is een onveranderlijke rechthoek waar het plaatsen van inhoud verboden is.
  • getX() / getY() — de huidige cursor in de auteursruimte.

Dit zijn idempotente leesbewerkingen. Ze genereren geen inhoud, verplaatsen de cursor niet en wijzigen de toestand niet. Gebruik ze om de resterende verticale ruimte te berekenen en beslis daarna of u verder schrijft of addPage() aanroept. U kunt een blok ook positioneren ten opzichte van een niet-beschrijfbaar gebied in plaats van een hardcoded offset te gebruiken.

Het API-oppervlak wordt gegenereerd uit PHPDoc. De belangrijkste toegangspunten bevinden zich in de traits \NextPDF\Core\Concerns\HasPages en 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);

Dit op zichzelf staande programma draait onder het testharnas. Het komt overeen met examples/34-inspect-layout-boxes.php. Het leest de paginageometrie uit, declareert een niet-beschrijfbaar gebied voor de voettekst en neemt voor elk blok een gegevensgestuurde beslissing. Als het volgende blok met een gebied zou botsen of voorbij de ondermarge zou lopen, voegt het een pagina toe in plaats van er overheen te schrijven.

<?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);

Verwachte standaarduitvoer (STDOUT). De waarden voor het paginavak weerspiegelen het standaard A4-paginaformaat, en de cursor begint bij de inhoudsoorsprong linksboven:

Page box: 595.28 x 841.89 pt
Cursor start: (<x>, <y>)
Pages used: 2 (page breaks decided from layout geometry)
  • Lees uit nadat de pagina bestaat. getPageWidth() en getPageHeight() geven de huidige pagina weer, dus roep ze aan na addPage(). Vóór de eerste pagina geven ze de geometrie van het standaardpaginaformaat terug, niet die van een pagina die u nog niet hebt toegevoegd.
  • Gebieden zijn rechthoeken in de auteursruimte. Een PageRegiony is de afstand in auteursruimte vanaf linksboven, consistent met getY(). Meng het niet met ruwe PDF-coördinaten vanuit linksonder.
  • Leesbewerkingen hebben geen neveneffecten. Geen van de querymethoden verplaatst de cursor of produceert inhoud. U kunt ze veilig in een strakke lus aanroepen; dat kost weinig.
  • Marges kunnen per pagina veranderen. Als u voor een latere pagina andere marges instelt, lees getMargins() dan opnieuw uit in plaats van de eerste waarde in de cache te bewaren.
  • Gebieden laten tekst niet automatisch herschikken. Een niet-beschrijfbaar gebied is een beperking die u moet naleven, geen automatische tekstomloopgrens. Het recipe toont de expliciete botsingscontrole. Bij vrij gepositioneerde schrijfbewerkingen verplaatst de engine inhoud nooit automatisch uit een gebied.

Elke methode hier is een eigenschapslezing. Ze draait in constante tijd, zonder geheugentoewijzing en zonder invoer of uitvoer. Het voorbeeld bouwt een klein document met meerdere pagina’s ruim binnen het budget van 1500 ms / 96 MB. Het reproduceerbaarheidsprofiel is semantisch, omdat de gegenereerde PDF de trailer /ID en aanmaakmetadata bevat. De waarneembare geometriebeslissingen van het voorbeeld zijn het belangrijkst, dus het testharnas valideert die beslissingen via een structurele abstract syntax tree (AST) plus metadatavergelijking in plaats van een byte-hash.

  • Dataresidentie en PII-mitigaties. Niet van toepassing. Het recipe leest geometrie uit en deelt door de aanroeper aangeleverde tekst in, dus het introduceert geen nieuw datapad. Pas dezelfde minimalisatie toe op de tekst die u plaatst als u overal elders zou doen.
  • Veilige telemetrie en logschoning. Het voorbeeld drukt geometriegetallen en een vaste voortgangsregel af. Het logt geen documenttekst.
  • Dreigingsmodel. Niet van toepassing. Het query-oppervlak is alleen-lezen en parseert geen externe invoer. Het is geen vertrouwensgrens.
  • Gedrag in FIPS-modus. Niet van toepassing. Er wordt geen cryptografische bewerking uitgevoerd.
BeweringSpecificatieClausulereference_id
Een pagina-object definieert zijn omvang via begrenzingsvakken (MediaBox).ISO 32000-2§7.7.3.3
De paginarechthoek is de inhoudsgrens.ISO 32000-2§7.7.3.3
Posities worden gemeten in de gebruikersruimte; één eenheid is 1/72 inch.ISO 32000-2§8.3.2

Dit recipe leest de geometrie uit die wordt gedefinieerd door de geciteerde ISO 32000-2-clausules over het paginavak en de gebruikersruimte. Het claimt geen volledige ISO 32000-2-conformiteit. Het lay-outquery-oppervlak steunt op de geciteerde clausules.