Layout: intestazioni, piè di pagina, colonne, opuscoli e gestione delle pagine
In breve
Sezione intitolata “In breve”Il modulo Layout contiene i motori per gli elementi accessori di pagina a cui delega la facciata Document: rendering di intestazione e piè di pagina, layout a più colonne, imposizione di opuscoli con cucitura a sella e operazioni strutturali sulle pagine. È un modulo piccolo e stabile, composto da sei classi, tutte @since 1.0.0.
Installazione
Sezione intitolata “Installazione”composer require nextpdf/core:^3Panoramica concettuale
Sezione intitolata “Panoramica concettuale”Layout (src/Layout/, sei classi, @since 1.0.0) è lo strato di motori alla base del concern HasLayout. Il codice dell’applicazione richiama i metodi della facciata su Document; il trait instrada ogni chiamata verso uno di questi motori. Nel manifest il modulo è contrassegnato con rischio standard e stabilità internal, con Core come unico dipendente. L’accesso avviene tramite la facciata, senza costruire direttamente le classi.
HeaderFooter esegue il rendering dell’intestazione e del piè di pagina ricorrenti. Conserva, per ciascuna banda, lo stato di titolo, descrizione, logo, font, margine e colore. Produce, su richiesta, gli operatori del flusso di contenuto PDF tramite renderHeader() e renderFooter(). Il piè di pagina predefinito stampa una stringa "page / total" allineata a destra. setHeaderCallback() e setFooterCallback() sostituiscono il layout predefinito con una closure fornita dal chiamante. getHeaderContentHeight() indica lo spazio verticale occupato dall’intestazione, così che il corpo della pagina possa iniziare al di sotto di essa. Quando il documento è in modalità PDF con tag, l’intestazione automatica viene soppressa a monte in HasPages, perché il contenuto dell’intestazione si trova al di fuori dell’albero delle strutture.
ColumnLayout gestisce il flusso a più colonne. setEqualColumns(int $count, float $totalWidth, float $gap = 5) suddivide una larghezza disponibile in colonne uguali. setColumnsArray() accetta posizioni e larghezze ColumnDefinition esplicite. Il cursore seleziona una colonna con selectColumn() oppure avanza con nextColumn(). getCurrentColumnX() / getCurrentColumnWidth() restituiscono la geometria della colonna attiva. Un numero di colonne non valido, uno spazio negativo o una larghezza di colonna calcolata non positiva generano PageLayoutException.
BookletLayout riordina le pagine per la rilegatura con cucitura a sella (piega centrale). reorderPages() completa l’elenco delle pagine fino a un multiplo di quattro (un foglio dell’opuscolo contiene quattro posizioni di pagina), quindi impone le pagine dall’esterno verso l’interno, così che i fogli piegati e pinzati si leggano nell’ordine corretto. getMarginAdjustments() restituisce, per ciascun lato, i margini interno (dorso) ed esterno (bordo) per una determinata posizione. getSheetCount() indica quanti fogli fronte-retro sono necessari per un determinato numero di pagine. Il riordino modifica unicamente la disposizione del contenuto. La sequenza sottostante delle pagine PDF rimane lineare, coerente con l’albero delle pagine, che definisce l’ordinamento delle pagine nel documento (ISO 32000-2 §7.7).
PageManager fornisce operazioni strutturali sulle pagine, separate dal rendering del contenuto. movePage(), copyPage() e deletePage() operano per riferimento su un array PageData. Le regioni di pagina (addPageRegion(), isInRegion(), getRegionOffset()) definiscono zone in cui non è consentita la scrittura. I gruppi di pagine (startPageGroup(), getGroupPageNo()) supportano la numerazione delle pagine per sezione. PageRegion e ColumnDefinition sono i due contenitori di valori utilizzati dai motori. Il modulo Writer serializza le pagine risultanti in un albero delle pagine la cui voce Kids è un array di riferimenti indiretti ai figli immediati di un nodo dell’albero delle pagine (ISO 32000-2 §7.7.3.2).
Superficie API
Sezione intitolata “Superficie API”| Simbolo | Tipo | Stabilità | Dalla versione |
|---|---|---|---|
HeaderFooter::setHeaderData(string, string, string, float): self | metodo | stabile | 1.0.0 |
HeaderFooter::setHeaderFont(string, float): self / setHeaderMargin(float): self | metodo | stabile | 1.0.0 |
HeaderFooter::setFooterFont(string, float): self / setFooterMargin(float): self | metodo | stabile | 1.0.0 |
HeaderFooter::setHeaderCallback(Closure): self / setFooterCallback(Closure): self | metodo | stabile | 1.0.0 |
HeaderFooter::getHeaderContentHeight(): float | metodo | stabile | 1.0.0 |
HeaderFooter::renderHeader(float, float, float, float, int, int): string | metodo | stabile | 1.0.0 |
HeaderFooter::renderFooter(float, float, float, float, int, int, string): string | metodo | stabile | 1.0.0 |
ColumnLayout::setEqualColumns(int, float, float): self | metodo | stabile | 1.0.0 |
ColumnLayout::setColumnsArray(array): self / resetColumns(): self | metodo | stabile | 1.0.0 |
ColumnLayout::selectColumn(int): self / nextColumn(): bool | metodo | stabile | 1.0.0 |
ColumnLayout::getCurrentColumnX(float): float / getCurrentColumnWidth(float): float | metodo | stabile | 1.0.0 |
BookletLayout::setBooklet(bool, float, float): void | metodo | stabile | 1.0.0 |
BookletLayout::reorderPages(array): array | metodo | stabile | 1.0.0 |
BookletLayout::getMarginAdjustments(int): array{left: float, right: float} | metodo | stabile | 1.0.0 |
BookletLayout::getSheetCount(int): int | metodo | stabile | 1.0.0 |
PageManager::movePage(int, int, array): void / copyPage(int, array): void / deletePage(int, array): void | metodo | stabile | 1.0.0 |
PageManager::addPageRegion(float, float, float, float): void / isInRegion(float, float): bool | metodo | stabile | 1.0.0 |
PageManager::getRegionOffset(float, float, float, float): float | metodo | stabile | 1.0.0 |
PageManager::startPageGroup(): void / getGroupPageNo(int): int | metodo | stabile | 1.0.0 |
PageRegion / ColumnDefinition | contenitore di valori | stabile | 1.0.0 |
Esempio di codice — Avvio rapido
Sezione intitolata “Esempio di codice — Avvio rapido”<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('Header and Footer');
$doc->setHeaderData( title: 'NextPDF Example', description: 'Header and Footer Demonstration',);$doc->setHeaderFont('helvetica', 10);$doc->setHeaderMargin(5);$doc->setFooterFont('helvetica', 8);$doc->setFooterMargin(10);
$doc->addPage();$doc->setFont('helvetica', 'B', 16);$doc->cell(0, 12, 'Document with Header and Footer', newLine: true);
$doc->save(__DIR__ . '/output/13-header-footer.pdf');Origine: examples/13-header-footer.php. L’intestazione viene resa a ogni addPage(); il piè di pagina viene reso quando la pagina viene emessa.
Esempio di codice — Produzione
Sezione intitolata “Esempio di codice — Produzione”Un callback del piè di pagina gestisce il testo del numero di pagina e il motore delle colonne controlla un corpo a due colonne. A entrambi i motori si accede tramite la facciata.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('Two-Column Report');
$doc->setFooterCallback(static function (Document $d): void { $d->setFont('helvetica', '', 8); $d->text(180.0, 285.0, 'Page ' . ($d->getPage() + 1));});
$doc->addPage();$doc->setEqualColumns(2, gap: 8);$doc->selectColumn(0);$doc->setFont('helvetica', '', 10);$doc->multiCell(0, 6, 'Left column flows here.');$doc->selectColumn(1);$doc->multiCell(0, 6, 'Right column flows here.');
$doc->save(__DIR__ . '/output/two-column-report.pdf');Origine: schema tratto da examples/13-header-footer.php.
Casi limite e insidie
Sezione intitolata “Casi limite e insidie”setEqualColumns()rifiuta un numero di colonne inferiore a 1, uno spazio negativo o un layout la cui larghezza di colonna calcolata non è positiva. Ciascuno di questi casi generaPageLayoutExceptionanziché restituire un layout degradato.selectColumn()ignora un indice fuori intervallo e mantiene la colonna corrente; non genera mai un’eccezione per un indice errato.nextColumn()restituiscefalsequando è già sull’ultima colonna.BookletLayout::reorderPages()completa fino a un multiplo di quattro con pagine vuote clonate dalle dimensioni dell’ultima pagina. Un elenco di pagine vuoto restituisce un array vuoto. Il riordino incide unicamente sulla disposizione; gli indici dimovePage()continuano a fare riferimento all’ordine logico.PageManager::movePage(),copyPage()edeletePage()ignorano silenziosamente un indice fuori intervallo: convalidano conisset()e restituiscono il controllo senza modificare l’array. Verificare esplicitamente l’indice quando una pagina mancante costituisce un errore del chiamante.getHeaderContentHeight()restituisce0.0quando l’intestazione è disabilitata oppure non ha né titolo né descrizione. Il corpo della pagina inizia quindi in corrispondenza del margine superiore.- In modalità PDF con tag l’intestazione automatica viene soppressa a monte. Creare un layout consapevole della struttura per i documenti accessibili.
Prestazioni
Sezione intitolata “Prestazioni”Il rendering di intestazione e piè di pagina aggiunge operatori al buffer della pagina attiva con costo O(contenuto degli accessori): il costo è proporzionale al titolo, alla descrizione e al separatore scritti, non alla dimensione del documento. I calcoli sulle colonne sono O(1) per chiamata. BookletLayout::reorderPages() è O(n) rispetto al numero di pagine, con un’unica passata di riempimento; il ciclo di imposizione tocca ciascuna posizione aggiunta una sola volta. I test sulle regioni di PageManager sono O(regioni) per punto; le operazioni sulle pagine sono splice di array O(n). Nessuno di questi motori conserva uno stato per pagina lungo l’intero documento, quindi non contribuiscono alla crescita della memoria nei documenti lunghi. Il costo di memoria dominante è il flusso di contenuto accumulato, descritto nel concetto di streaming e memoria. Il gate del budget di latenza e memoria della pipeline HTML è documentato in PERFORMANCE-BUDGETS; è circoscritto al percorso di rendering HTML e non vincola direttamente questi motori di layout. Il performance_budget di 1500 ms / 64 MB è l’inviluppo complessivo per l’avvio rapido, non un contratto per singola chiamata.
Note sulla sicurezza
Sezione intitolata “Note sulla sicurezza”Questi motori utilizzano stringhe e un percorso del logo forniti dal chiamante. Il percorso del logo passa attraverso il motore delle immagini, che convalida il file prima che venga incorporato. renderHeader() e renderFooter() applicano l’escape a titolo, descrizione e testo del numero di pagina tramite l’escaper centralizzato delle stringhe PDF prima che raggiungano il flusso di contenuto, in modo che il testo del chiamante non possa uscire dalla grammatica delle stringhe letterali. Un callback di intestazione o piè di pagina esegue codice del chiamante con lo stesso livello di attendibilità del resto del documento: trattare di conseguenza qualsiasi dato esterno che legga. Le operazioni sulle pagine di PageManager spostano riferimenti a PageData esistenti; non analizzano byte non attendibili.
Conformità
Sezione intitolata “Conformità”| Asserzione | Standard | Clausola | Evidenza |
|---|---|---|---|
| Il riordino delle pagine per l’output a opuscolo modifica solo la disposizione; l’albero delle pagine continua a definire l’ordinamento lineare delle pagine nel documento. | ISO 32000-2 | §7.7 | |
La voce Kids del nodo serializzato dell’albero delle pagine è un array di riferimenti indiretti ai figli immediati di tale nodo. | ISO 32000-2 | §7.7.3.2 |
Le clausole sono parafrasate e ancorate al glossario; non viene riprodotto alcun testo normativo.
Vedere anche
Sezione intitolata “Vedere anche”- Core / trait HasLayout — il concern della facciata che compone questi motori.
- Core / trait HasPages — dimensione della pagina e margini usati dai calcoli sulle colonne.
- Writer — l’emettitore di oggetti PDF e dell’albero delle pagine che serializza le pagine impaginate.
- Streaming e memoria — perché i motori per gli accessori non mantengono alcuno stato per pagina e come il percorso di rendering è vincolato dalla memoria.
- HTML / Vincoli di streaming (ADR-001) — la motivazione dell’ambito dello streaming a passaggio singolo.