Ga naar inhoud

Lange HTML over meerdere pagina's pagineren

Gebruik automatische pagina-einden om lange inhoud over meerdere pagina’s te laten lopen. Voeg een overzicht toe, zodat lezers tussen secties kunnen springen. Dit recipe volgt examples/12-bookmarks-and-toc.php.

Terminal window
composer require nextpdf/core:^3

Gebruik deze constraint voor het pakket nextpdf/core. Het voorbeeld draait op PHP 8.4.

setAutoPageBreak(true, $margin) instrueert de engine om een nieuwe pagina te beginnen voordat de inhoud de ondermargedrempel overschrijdt. De engine fragmenteert lange tekst die met multiCell() of writeHtml() wordt geschreven op die grens. De Cascading Style Sheets (CSS) Fragmentation-module (css_break_3) heeft in de ondersteuningsmatrix de beoordeling Verified. Deze module ondersteunt het afbreekgedrag in de Hypertext Markup Language (HTML)-pijplijn.

bookmark($title, $level) voegt een overzichtsitem toe voor de huidige positie. Een overzichtsitem in Portable Document Format (PDF) koppelt een bestemming, zodat lezers rechtstreeks naar een pagina kunnen springen (ISO 32000-2). De engine schrijft die bestemming als de Dest-vermelding van het item (ISO 32000-2). Gebruik het argument level om items te nesten in een hiërarchische inhoudsopgave in de zijbalk van de viewer.

De pijplijn blijft single-pass (ADR-001). De engine bepaalt de paginering tijdens het uitzenden van de stream, zonder bewaarde lay-outboom.

  • setAutoPageBreak(bool $enabled, float $margin = 20): staticNextPDF\Core\Concerns\HasPages.
  • bookmark(string $title, int $level = 0, float $y = -1): staticNextPDF\Core\Concerns\HasNavigation.
  • multiCell(...) / writeHtml(string $html): staticNextPDF\Core\Concerns\HasTextOutput.

De volledige PHPDoc-tabel wordt gegenereerd vanuit de broncode.

<?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->bookmark('Section 1', level: 0);
$doc->setFont('helvetica', '', 11);
for ($i = 1; $i <= 80; $i++) {
$doc->multiCell(0, 7, "Paragraph {$i} of a long flowing document.");
}
$doc->save(__DIR__ . '/out.pdf');

Dit zelfstandige voorbeeld draait in de harness. Het bouwt een document met meerdere hoofdstukken, een geneste overzichtsstructuur en automatische pagina-einden, en weerspiegelt examples/12-bookmarks-and-toc.php.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Bookmarks and Navigation');
$doc->setPrintHeader(false);
$doc->setPrintFooter(false);
$doc->setAutoPageBreak(true, margin: 25);
$chapters = [
'Chapter 1: Introduction' => ['What is NextPDF?', 'Key Features'],
'Chapter 2: Getting Started' => ['Installation', 'Your First PDF'],
'Chapter 3: Advanced Topics' => ['Worker-safe Architecture', 'Streaming Output'],
];
$body = 'NextPDF is a modern PDF 2.0 library for PHP. This paragraph is '
. 'repeated so the content overflows the page and the engine inserts '
. 'an automatic page break at the bottom-margin threshold.';
foreach ($chapters as $chapter => $sections) {
$doc->addPage();
$doc->bookmark($chapter, level: 0);
$doc->setFont('helvetica', 'B', 18);
$doc->cell(0, 12, $chapter, newLine: true);
$doc->ln(3);
foreach ($sections as $section) {
$doc->bookmark($section, level: 1);
$doc->setFont('helvetica', 'B', 14);
$doc->cell(0, 10, $section, newLine: true);
$doc->setFont('helvetica', '', 11);
for ($i = 0; $i < 12; $i++) {
$doc->multiCell(0, 7, $body);
}
$doc->ln(4);
}
}
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');
$doc->save($out !== false ? $out : __DIR__ . '/paginate-long-html.pdf');
echo "Wrote paginate-long-html.pdf\n";

Verwachte standaarduitvoer (STDOUT):

Wrote paginate-long-html.pdf
  • Uitschakelen en vergeten. Wanneer het automatische pagina-einde is uitgeschakeld, kapt de engine inhoud voorbij de ondermarge af in plaats van deze door te laten lopen. Schakel het opnieuw in vóór lange inhoud.
  • Niet-splitsbare inhoud. Eén enkel blok dat hoger is dan de bruikbare paginahoogte kan een UnsplittableContentException veroorzaken. Dat kan gebeuren bij een zeer hoge tabelrij of grote afbeelding. Splits de broninhoud.
  • Bladwijzer vóór inhoud. Roep bookmark() aan op de positie waar je wilt dat de bestemming naar verwijst. Plaats het direct vóór de volgende kop, op de gewenste pagina.
  • Kop- en voettekst reserveren ruimte. Een kop- of voettekst verkleint de bruikbare inhoudshoogte, en de afbreekdrempel houdt daar rekening mee. Door beide uit te schakelen, zoals dit voorbeeld doet, beschik je over de volledige hoogte van het tekstvlak.
  • Nesting van het overzicht. level is de nestingdiepte. Een onderliggend item op level: 1 moet volgen op een bovenliggend item op level: 0. Anders vlakt de viewer de overzichtsstructuur af.

De engine bepaalt de paginering in één emissiedoorloop. De kosten zijn lineair in de lengte van de inhoud, O(n). Het budget is wall_ms: 2000, peak_mb: 96. De doorlooptijd ligt iets hoger dan bij recipes van één pagina, omdat de cross-reference (xref) over meerdere pagina’s en het samenstellen van het overzicht extra werk met zich meebrengen. Het streamingmodel houdt het geheugengebruik begrensd, en het overzicht blijft een kleine vlakke lijst.

Fragment uit de CSS-ondersteuningsmatrix (alleen Verified-rijen)

Sectie met titel “Fragment uit de CSS-ondersteuningsmatrix (alleen Verified-rijen)”

Deze tabel geeft alleen de Verified-rijen weer uit de CSS-ondersteuningsmatrix waarvan de juistheid is gecontroleerd.

W3C-moduleNiveauStatusBewijs
CSS Fragmentation (css_break_3)3Verifiedsrc/Html/Fragmentation/, tests/Unit/Html/PagedMedia/
CSS Table (css_tables_3)3Verifiedsrc/Html/Table/ + golden-PDF’s
CSS Cascading and Inheritance (css_cascade_3)3Verifiedsrc/Html/Cascade/

@page-selectors voor benoemde pagina’s behoren tot CSS Paged Media. Raadpleeg de matrix voor de huidige beoordeling van die module voordat je erop vertrouwt.

Beperkingen van single-pass streaming (ADR-001)

Sectie met titel “Beperkingen van single-pass streaming (ADR-001)”

De engine zendt pagina-einden uit terwijl de stream loopt. Omdat er geen bewaarde boom is die opnieuw kan worden doorlopen, is elke afbreekbeslissing definitief. Sommige inhoud, zoals een cross-reference, heeft het definitieve paginanummer pas nodig nadat de lay-out vastligt. Die inhoud is beperkt, dus houd bij het schrijven rekening met die beperking.

Paginering hoort bij de pagina-einde-controller, niet bij de parser. De parser zendt geen ruwe pagina-overgangsoperatoren uit; hij vraagt een afbreking aan via het controllercontract.

Het streamingmodel houdt de buffer van de huidige pagina en de vlakke overzichtslijst vast, niet alle pagina’s tegelijk. Een zeer lang document blijft binnen het ADR-020-plafond omdat de engine voltooide pagina’s leegmaakt. Tabellen en flex-containers blijven zich houden aan de grens van 5,000 nodes per context.

Een kwaadwillend document kan geen onbegrensd geheugengebruik afdwingen. De limieten voor elementen en nesting (ADR-001), samen met het node-budget per context (ADR-020), begrenzen het werk. Valideer de lengte en structuur van lange inhoud die gebruikers aanleveren. De engine geeft een door een aanvaller gecontroleerde overzichtstitel weer als tekst en interpreteert die nooit.

BeweringSpecificatieClausulereference_id
Elk overzichtsitem kan aan een bestemming worden gekoppeld zodat de gebruiker er rechtstreeks naartoe springt.ISO 32000-2iso32000_2_sec12#x1.x5.p4
De Dest-vermelding van een overzichtsitem benoemt de bestemming die wordt weergegeven wanneer het item wordt geactiveerd.ISO 32000-2iso32000_2_sec12#x1.x11.p30

Dit recipe laat zien hoe NextPDF lange inhoud over pagina’s laat lopen en een overzicht opbouwt. De ondersteuningsmatrix beoordeelt CSS Fragmentation als Verified.

Niet van toepassing.