Ga naar inhoud

Een document met meerdere pagina's en automatische pagina-einden opbouwen

Stel een document samen dat over veel pagina’s doorloopt. Voeg stapsgewijs inhoud toe. Wanneer setAutoPageBreak() is ingeschakeld, start de lay-out-engine een nieuwe pagina zodra de cursor de ondermarge bereikt. Lees na save() met getNumPages() het uiteindelijke aantal pagina’s uit. Dit recipe volgt examples/05-multi-page.php.

Tijdens save() schrijft de engine de tekeninstructies van elke pagina naar een content-stream. ISO 32000-2 §7.7.3.3 definieert de Contents van een pagina als één stream of als een array van streams die in volgorde worden aaneengeschakeld. Uitvoer met meerdere pagina’s bestaat daarom uit een reeks pagina-objecten, niet uit één enkele buffer.

Terminal window
composer require nextpdf/core:^3

Je hebt geen optionele extensie nodig. Dit recipe draait op de backport-matrix voor PHP 8.1–8.4. getNumPages() en setAutoPageBreak() zijn allebei stabiel sinds 1.0.0.

Een NextPDF-document is een paginaboom. Terwijl je inhoud toevoegt, beweegt een interne cursor (getY()) omlaag over de pagina. Wanneer automatische pagina-einden zijn ingeschakeld, controleert de engine vóór elk inhoudsblok hoeveel verticale ruimte er nog over is. Past het blok niet boven de ondermarge, dan sluit de engine de huidige pagina af en roept addPage() voor je aan. De ondermarge die je aan setAutoPageBreak() doorgeeft, is de triggerdrempel.

Attributen op paginaniveau, zoals de media box, zijn overerfbaar. ISO 32000-2 §7.7.3.4 bepaalt dat een attribuut dat in een pagina-object ontbreekt, uit een bovenliggende knoop in de paginaboom wordt afgeleid. NextPDF stelt voor het hele document één consistent paginaformaat in, zodat elke gegenereerde pagina dezelfde geometrie gebruikt en je dit niet per pagina hoeft te herhalen.

Het API-oppervlak wordt gegenereerd uit PHPDoc. Dit recipe gebruikt deze methoden:

  • Document::createStandalone(): self — maakt een geïsoleerd document aan.
  • setAutoPageBreak(bool $enabled, float $margin = 20): static — schakelt automatische pagina-einden in. $margin is de triggerdrempel voor de ondermarge in millimeters.
  • addPage(?PageSize $size = null, Orientation $orientation = Orientation::Portrait): static — start de eerste pagina en elke expliciet toegevoegde pagina.
  • multiCell(...): static / cell(...): static — renderen doorlopende of vaste tekstblokken. De controle op pagina-einden meet deze blokken.
  • getNumPages(): int — het aantal pagina’s na de lay-out.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setAutoPageBreak(true, margin: 25);
$doc->addPage();
$doc->setFont('helvetica', '', 11);
for ($i = 1; $i <= 60; $i++) {
$doc->multiCell(0, 7, "Line {$i}: content flows until the page is full, "
. 'then the engine starts a new page automatically.');
}
$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/multi-page.pdf');
echo 'Pages: ' . $doc->getNumPages() . "\n";

Dit is het volledige voorbeeld dat klaar is voor de harness. Het respecteert NEXTPDF_COOKBOOK_OUTPUT, die door de harness wordt ingesteld; stuur de PDF dus niet naar STDOUT. Het voegt zelf geen entropie toe. Wanneer de harness het voorbeeld uitvoert, legt DeterministicMode de klok, /ID en de branding vast.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Multi-Page Document');
// Enable automatic page breaks. The 25 mm bottom margin is the trigger:
// when the cursor would cross it, the engine flushes the page and adds
// a new one before the next block is drawn.
$doc->setAutoPageBreak(true, margin: 25);
$doc->addPage();
$doc->setFont('helvetica', 'B', 18);
$doc->cell(0, 12, 'Multi-Page Document Example', newLine: true);
$doc->ln(5);
for ($chapter = 1; $chapter <= 3; $chapter++) {
$doc->setFont('helvetica', 'B', 14);
$doc->cell(0, 10, "Chapter {$chapter}: Lorem Ipsum", newLine: true);
$doc->setFont('helvetica', '', 11);
for ($para = 1; $para <= 5; $para++) {
$text = "Paragraph {$para} of Chapter {$chapter}. "
. 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. '
. 'Sed do eiusmod tempor incididunt ut labore et dolore magna '
. 'aliqua. Ut enim ad minim veniam, quis nostrud exercitation '
. 'ullamco laboris nisi ut aliquip ex ea commodo consequat.';
$doc->multiCell(0, 7, $text);
$doc->ln(3);
}
$doc->ln(5);
}
// The harness sets NEXTPDF_COOKBOOK_OUTPUT; honour it. STDOUT stays free
// for progress text only.
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/multi-page.pdf';
$doc->save($out);
echo 'Created multi-page.pdf with ' . $doc->getNumPages() . " pages\n";
  • Automatisch pagina-einde uitgeschakeld. Met setAutoPageBreak(false, …) wordt inhoud die voorbij de ondermarge gaat op de pagina afgesneden in plaats van door te stromen, en blijft het document op één pagina. Schakel het in voor doorlopende inhoud.
  • Eén blok dat hoger is dan de pagina. De engine splitst intern een multiCell waarvan de tekst de afdrukbare hoogte overschrijdt. Eén ondeelbaar blok dat hoger is dan het bruikbare gebied, zoals een hoge afbeelding, wordt echter één keer geplaatst en loopt over. Splits het zelf op.
  • De eerste addPage() blijft vereist. cell() roept addPage() indien nodig aan wanneer er geen pagina bestaat. Roep addPage() toch expliciet aan, zodat het formaat en de oriëntatie van de eerste pagina deterministisch blijven.
  • Marge-eenheden. De marge van setAutoPageBreak() wordt in het standaardeenhedenstelsel uitgedrukt in millimeters, niet in punten.

getNumPages() is O(1). De methode leest een teller uit en voert de lay-out niet opnieuw uit. Het geheugengebruik schaalt mee met de bewaarde inhoud, niet met het aantal pagina’s. De engine schrijft voltooide pagina’s naar de uitvoerbuffer zodra ze klaar zijn — het streamingmodel in één doorloop (ADR-001). Het budget van 2000 ms / 64 MB volstaat voor documenten met enkele honderden pagina’s tekst op de referentiehost.

Dit recipe schrijft alleen de tekst die je code aanlevert. Het doet geen invoerparsing, netwerktoegang of deserialisatie. Behandel tekst uit externe bronnen als niet-vertrouwd en pas vóór het renderen een lengtelimiet toe. De engine legt geen limiet op applicatieniveau op aan de inhoudsgrootte.

BeweringSpecClausulereference_id
De Contents van een pagina is één enkele stream of een geordende, aaneengeschakelde array van streams.ISO 32000-2§7.7.3.3
Een overerfbaar pagina-attribuut dat in een pagina-object ontbreekt, wordt afgeleid van een bovenliggende knoop in de paginaboom.ISO 32000-2§7.7.3.4
De trailer-/ID is een bestands-id bestaande uit twee byte-strings (vereist in PDF 2.0).ISO 32000-2§7.5.5

Reproduceerbaarheidsprofiel — structureel (waarom niet bitsgewijs). Elk opgeslagen document bevat een trailer-/ID waarvan de twee byte-strings samen een bestands-id vormen (ISO 32000-2 §7.5.5, hierboven). Het tweede element is niet stabiel tussen uitvoeringen, dus de ruwe bytes verschillen per uitvoering, zelfs bij identieke inhoud. De harness vergelijkt de structuur die met qpdf is genormaliseerd, waaruit /ID, /CreationDate en /ModDate worden verwijderd. Dit recipe beschrijft hoe NextPDF de structuur produceert. Het claimt geen algemene ISO 32000-2-conformiteit.

Niet van toepassing. Het samenstellen van meerdere pagina’s met automatische pagina-einden is een Core-functie, zonder Premium-drempel.