Przejdź do głównej zawartości

Tworzenie dokumentu wielostronicowego z automatycznymi podziałami stron

Utwórz dokument obejmujący wiele stron. Dodawaj treść sukcesywnie. Po włączeniu setAutoPageBreak() silnik układu rozpoczyna nową stronę, gdy kursor osiągnie dolny margines. Po wywołaniu save() odczytaj ostateczną liczbę stron za pomocą getNumPages(). Ten przepis opiera się na examples/05-multi-page.php.

W trakcie wywołania save() silnik zapisuje znaczniki każdej strony w strumieniu treści. ISO 32000-2 §7.7.3.3 definiuje element Contents strony jako jeden strumień albo tablicę strumieni połączonych w kolejności. Wynik wielostronicowy jest więc sekwencją obiektów stron, a nie pojedynczym buforem.

Okno terminala
composer require nextpdf/core:^3

Nie jest wymagane żadne opcjonalne rozszerzenie. Ten przepis działa w ramach macierzy backportów PHP 8.1–8.4. Metody getNumPages() oraz setAutoPageBreak() są stabilne od wersji 1.0.0.

Dokument NextPDF ma postać drzewa stron. W miarę dodawania treści wewnętrzny kursor (getY()) przesuwa się w dół strony. Po włączeniu automatycznych podziałów stron silnik sprawdza pozostałe miejsce w pionie przed każdym blokiem treści. Jeśli blok nie zmieści się nad dolnym marginesem, silnik finalizuje bieżącą stronę i automatycznie wywołuje addPage(). Dolny margines przekazany do setAutoPageBreak() jest progiem wyzwalającym.

Atrybuty poziomu strony, takie jak media box, są dziedziczone. ISO 32000-2 §7.7.3.4 określa, że atrybut pominięty w obiekcie strony jest rozwiązywany na podstawie nadrzędnego węzła drzewa stron. NextPDF ustawia jeden spójny rozmiar strony w całym dokumencie, więc każda wygenerowana strona korzysta z tej samej geometrii i nie trzeba powtarzać tej konfiguracji dla każdej strony.

Powierzchnia API jest generowana z PHPDoc. Ten przepis korzysta z następujących metod:

  • Document::createStandalone(): self — tworzy samodzielny dokument.
  • setAutoPageBreak(bool $enabled, float $margin = 20): static — włącza automatyczne podziały stron. $margin to próg dolnego marginesu wyrażony w milimetrach.
  • addPage(?PageSize $size = null, Orientation $orientation = Orientation::Portrait): static — rozpoczyna pierwszą stronę oraz każdą stronę dodaną jawnie.
  • multiCell(...): static / cell(...): static — generują przepływające albo stałe bloki tekstu. Mechanizm kontroli podziału strony mierzy właśnie te bloki.
  • getNumPages(): int — liczba stron po wykonaniu układu.
<?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";

To kompletny przykład, gotowy do uruchomienia w środowisku testowym. Uwzględnia zmienną NEXTPDF_COOKBOOK_OUTPUT, ustawianą przez środowisko testowe, dlatego nie wypisuje pliku PDF do STDOUT. Nie dodaje własnej entropii. Po uruchomieniu przez środowisko testowe tryb DeterministicMode ustala stały zegar, /ID oraz elementy marki.

<?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";
  • Wyłączony automatyczny podział strony. Przy setAutoPageBreak(false, …) treść wykraczająca poza dolny margines jest przycinana na stronie zamiast przechodzić na następną, a dokument pozostaje jednostronicowy. Włącz automatyczny podział dla płynącej treści.
  • Pojedynczy blok wyższy niż strona. Silnik wewnętrznie dzieli tekst w multiCell, jeśli tekst przekracza wysokość obszaru drukowania. Jednak pojedynczy, niepodzielny blok wyższy niż obszar użytkowy, na przykład wysoki obraz, jest umieszczany raz i wychodzi poza stronę. Podziel taki blok samodzielnie.
  • Pierwsze wywołanie addPage() nadal jest wymagane. cell() wywołuje addPage() na żądanie, jeśli nie ma jeszcze żadnej strony. Mimo to wywołuj addPage() jawnie, aby rozmiar i orientacja pierwszej strony pozostały deterministyczne.
  • Jednostki marginesu. Margines w setAutoPageBreak() jest wyrażony w milimetrach w domyślnym systemie jednostek, a nie w punktach.

getNumPages() ma złożoność O(1). Odczytuje licznik i nie uruchamia układu ponownie. Zużycie pamięci skaluje się wraz z przechowywaną treścią, a nie z liczbą stron. Silnik przekazuje ukończone strony do bufora wyjściowego w miarę ich finalizowania – to model strumieniowania jednoprzebiegowego (ADR-001). Budżet 2000 ms / 64 MB obejmuje dokumenty z kilkuset stronami tekstu na hoście referencyjnym.

Ten przepis zapisuje wyłącznie tekst dostarczony przez kod aplikacji. Nie wykonuje żadnego parsowania danych wejściowych, nie korzysta z sieci ani nie przeprowadza deserializacji. Każdy tekst pochodzący z zewnętrznego źródła traktuj jako niezaufany i przed renderowaniem nałóż limit długości. Silnik nie narzuca limitu rozmiaru treści na poziomie aplikacji.

StwierdzenieSpecyfikacjaKlauzulareference_id
Element Contents strony to pojedynczy strumień albo uporządkowana tablica strumieni łączonych w kolejności.ISO 32000-2§7.7.3.3
Jeżeli dziedziczony atrybut strony pominięto w obiekcie strony, jest on rozwiązywany na podstawie nadrzędnego węzła drzewa stron.ISO 32000-2§7.7.3.4
Element /ID w zwiastunie to identyfikator pliku złożony z dwóch ciągów bajtów (wymagany w PDF 2.0).ISO 32000-2§7.5.5

Profil odtwarzalności — strukturalny (dlaczego nie bitowy). Każdy zapisany dokument zawiera w zwiastunie element /ID, którego dwa ciągi bajtów stanowią identyfikator pliku (ISO 32000-2 §7.5.5, powyżej). Drugi ciąg nie jest stabilny między uruchomieniami, więc surowe bajty różnią się między kolejnymi uruchomieniami nawet przy identycznej treści. Środowisko testowe porównuje strukturę znormalizowaną przez narzędzie qpdf, które usuwa elementy /ID, /CreationDate oraz /ModDate. Ten przepis opisuje, jak NextPDF tworzy tę strukturę. Nie jest to ogólne zapewnienie o zgodności z ISO 32000-2.

Nie dotyczy. Komponowanie dokumentów wielostronicowych z automatycznymi podziałami stron jest funkcją Core i nie jest objęte bramką Premium.