Eseguire il rendering dell'HTML in una pagina PDF
In sintesi
Sezione intitolata “In sintesi”Questa ricetta mostra come trasformare un frammento di HTML e CSS in contenuto di una pagina PDF con un solo metodo, writeHtml(). Passando markup al metodo, si ottiene il rendering di una pagina formattata. La versione completa ed eseguibile di questo codice è examples/08-html-basic.php. Seguire i passaggi seguenti oppure copiare direttamente l’esempio.
NextPDF legge l’HTML in un’unica passata e invia il risultato in streaming direttamente nella pagina. Si tratta di una pipeline di streaming a passata singola. Non è necessario comprendere questo modello per usare la ricetta, ma è utile tenerlo presente perché determina alcune delle regole illustrate più avanti in questa pagina.
Installazione
Sezione intitolata “Installazione”composer require nextpdf/core:^3Questo comando installa il pacchetto nextpdf/core. Gli esempi di questa pagina vengono eseguiti su PHP 8.4 e il runtime supportato è >=8.4 <9.0.
Panoramica concettuale
Sezione intitolata “Panoramica concettuale”writeHtml() accetta una stringa di HTML e la disegna nella pagina corrente, a partire dalla posizione corrente del cursore. Ecco cosa accade all’interno, passo dopo passo. Per prima cosa, il motore analizza l’HTML una sola volta e lo suddivide in un elenco di token (HtmlTokenizer). Quindi percorre l’elenco da sinistra a destra (HtmlParser). Per ogni elemento, scrive in un buffer le istruzioni di disegno PDF corrispondenti — gli operatori del flusso di contenuto. Il motore non crea né mantiene in memoria un albero degli elementi tra una chiamata e l’altra. È una scelta progettuale deliberata: il modello di streaming a passata singola, documentato in ADR-001.
Ogni elemento di blocco supportato diventa un riquadro di impaginazione e ogni sequenza di testo diventa un operatore di visualizzazione del testo. Gli stili provenienti dagli attributi style inline e da un blocco <style> vengono risolti tramite la cascata CSS — le regole standard che stabiliscono quale stile prevale quando se ne applica più di uno. L’andata a capo, l’allineamento e la spaziatura del testo seguono il modello CSS Text, che regola la trasformazione del testo di origine in testo formattato e suddiviso in righe (W3C CSS Text Level 3).
Se non si sceglie un font, il testo del corpo utilizza un tipo di carattere predefinito. Questa impostazione predefinita è un font Type 1 standard, uno dei 14 font standard indicati in ISO 32000-2. Cambia solo quando si registra e si seleziona un font personalizzato oppure quando un profilo di conformità richiede a NextPDF di incorporare un font sostitutivo.
È bene chiarire subito un punto: NextPDF supporta un sottoinsieme di HTML e CSS, non l’intero standard di HTML o di CSS. Questa ricetta riguarda tale sottoinsieme supportato e non dichiara il supporto completo di HTML o CSS. Per lo stato esatto e verificato di ciascun modulo, vedere la matrice di supporto CSS.
Superficie dell’API
Sezione intitolata “Superficie dell’API”La firma del metodo è writeHtml(string $html): static. È dichiarato nell’interfaccia NextPDF\Contracts\PdfDocumentInterface e implementato in NextPDF\Core\Concerns\HasTextOutput. Esegue il rendering nella pagina corrente e ne crea una se non ne esiste ancora nessuna. La tabella PHPDoc completa per il metodo viene generata dal codice sorgente.
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('HTML Basic');$doc->addPage();
$doc->writeHtml('<h1>HTML Rendering in NextPDF</h1><p>Rendered with <strong>writeHtml()</strong>.</p>');
$doc->save(__DIR__ . '/out.pdf');Esempio di codice — Produzione
Sezione intitolata “Esempio di codice — Produzione”Questo è l’esempio completo e autonomo, ed è quello eseguito dal test harness. Corrisponde a examples/08-html-basic.php. Anziché impostare in modo fisso un percorso di output, scrive nella posizione fornita dall’harness, così l’harness di riproducibilità può eseguire lo script due volte e confrontare i risultati.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('HTML Basic');$doc->addPage();
$html = <<<'HTML'<h1 style="color: #1E3A8A;">HTML Rendering in NextPDF</h1>
<p>NextPDF renders <strong>HTML content</strong> directly into PDF pages.This is the recommended approach for <em>mixed formatting</em>.</p>
<h2>Supported elements</h2>
<ul> <li>Headings (h1-h6)</li> <li>Paragraphs with <strong>bold</strong> and <em>italic</em></li> <li>Ordered and unordered lists</li> <li>Tables with borders and alignment</li> <li>Inline styles (color, font-size, margin)</li></ul>
<h2>Ordered list</h2>
<ol> <li>Create a Document instance</li> <li>Add pages and content</li> <li>Call save() or output()</li></ol>HTML;
$doc->writeHtml($html);
// The harness sets NEXTPDF_COOKBOOK_OUTPUT and runs this script twice.// Honour it: do not hard-code a path, do not echo the PDF to STDOUT.$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');$doc->save($out !== false ? $out : __DIR__ . '/render-html-to-pdf.pdf');
echo "Wrote render-html-to-pdf.pdf\n";STDOUT previsto:
Wrote render-html-to-pdf.pdfCasi limite e insidie
Sezione intitolata “Casi limite e insidie”- Avanzamento del cursore.
writeHtml()sposta il cursore alla fine del contenuto sottoposto a rendering. Una successiva chiamata acell()o una seconda chiamata awriteHtml()prosegue da quel punto, non dall’inizio della pagina. - Nessuna pagina ancora presente. Se non esiste alcuna pagina,
writeHtml()ne aggiunge una prima del rendering. Chiamare esplicitamenteaddPage()quando è necessario impostare prima un formato di pagina specifico. - Limiti di elementi e annidamento. Il motore di streaming applica un limite di
50,000elementi e di 100 livelli di annidamento (ADR-001). Un documento che li supera viene rifiutato anziché troncato in modo silenzioso. - Markup non supportato. Gli elementi e le proprietà esterni al sottoinsieme supportato vengono ignorati o gestiti tramite fallback; non generano eccezioni. Verificare la copertura nella matrice di supporto CSS prima di fare affidamento su una proprietà.
- Risorse esterne. Le immagini e i fogli di stile remoti sono regolati dai criteri relativi alle risorse esterne; i criteri predefiniti non recuperano URL remoti arbitrari.
Prestazioni
Sezione intitolata “Prestazioni”Poiché la tokenizzazione e il rendering avvengono in un’unica passata sull’input, il costo cresce in modo lineare con il numero di token — ovvero O(n). Il budget predefinito per questa ricetta è wall_ms: 1500, peak_mb: 96. Dato che il motore invia l’output in streaming e non mantiene alcun DOM in memoria, il picco di memoria dipende dalle dimensioni del buffer del flusso di contenuto e dello stack di stili attivo, non dalle dimensioni dell’intero documento.
Estratto della matrice di supporto CSS (solo righe verificate)
Sezione intitolata “Estratto della matrice di supporto CSS (solo righe verificate)”Qui sono riportate solo le righe classificate come Verificate nella matrice di supporto CSS sottoposta ad audit di veridicità. «Verificato» significa un’implementazione in src/Html/ più una suite consistente di fixture dedicate che supera i test in modo deterministico secondo il profilo strutturale.
| Modulo W3C | Livello | Stato | Evidenza |
|---|---|---|---|
CSS Flexible Box Layout (css_flexbox_1) | 1 | Verificato | src/Html/Flex/, tests/Unit/Html/Flex/ |
CSS Grid Layout (css_grid_1) | 1 | Verificato | src/Html/Grid/, corpus WPT |
CSS Cascading and Inheritance (css_cascade_3) | 3 | Verificato | src/Html/Cascade/, tests/Unit/Html/Cascade/ |
CSS Table (css_tables_3) | 3 | Verificato | src/Html/Table/, fixture di tabella + PDF golden |
CSS Fonts (css_fonts_4) | 4 | Verificato | src/Html/FontFace/, tests/Unit/Html/FontFace/ |
Proprietà come text-align, text-indent e color sono classificate come «Dichiarate» nella matrice (implementate, senza fixture di modulo dedicata) e, per scelta, non sono elencate qui come Verificate.
Vincoli dello streaming a passata singola (ADR-001)
Sezione intitolata “Vincoli dello streaming a passata singola (ADR-001)”Il motore HTML non mantiene alcun DOM. Lo stato è un cursore scalare più uno stack di stili push/pop; i nodi di testo costituiti solo da spazi vuoti vengono scartati in fase di tokenizzazione. Di conseguenza, un elemento successivo non può ridefinire lo stile di uno precedente e i selettori che richiedono il contesto dell’intero albero (ad esempio, i casi complessi di :has()) sono soggetti ai vincoli di ADR-006. Pianificare un’impaginazione che dipenda solo dall’ordine del documento.
Contratti tra livelli (ADR-010)
Sezione intitolata “Contratti tra livelli (ADR-010)”L’analisi, l’impaginazione e il disegno sono livelli distinti. Il parser non emette operatori di disegno raw e il dispatch dell’impaginazione non analizza il CSS; oltrepassare tali confini introduce il debito di accoppiamento vietato da ADR-010. Per gli autori delle ricette, ciò significa che il punto di ingresso pubblico è writeHtml() — non accedere ai componenti interni del parser.
Budget di memoria per documenti di grandi dimensioni
Sezione intitolata “Budget di memoria per documenti di grandi dimensioni”Secondo ADR-020, i contesti di formattazione con ambito di contenitore (flex, table) possono costruire un sotto-albero effimero, limitato a 5,000 nodi per contesto, con una profondità di 20 livelli, un limite massimo di memoria attiva di 50 MB tra i contesti attivi e 10 livelli di annidamento. Al di fuori di tali contesti, il modello di streaming non mantiene alcun albero. Mantenere le singole tabelle e i contenitori flex entro il limite di nodi per ottenere un consumo di memoria prevedibile.
Note sulla sicurezza
Sezione intitolata “Note sulla sicurezza”Considerare l’input HTML come non attendibile. NextPDF non esegue script e i criteri predefiniti relativi alle risorse esterne non recuperano URL remoti arbitrari; pertanto, il motore stesso è conservativo. Ciononostante, convalidare o sottoporre a sanitizzazione qualsiasi HTML assemblato a partire da input dell’utente prima di eseguirne il rendering. Anche i limiti di elementi e annidamento offrono protezione: delimitano la quantità di lavoro che un documento ostile o malformato può richiedere.
Conformità
Sezione intitolata “Conformità”| Dichiarazione | Specifica | Clausola | reference_id |
|---|---|---|---|
| CSS Text controlla la conversione del testo di origine in testo formattato e suddiviso in righe. | W3C CSS Text Level 3 | css_text_3#x1.x2.p4 | |
| Il tipo di carattere predefinito del corpo del testo si risolve in un font Type 1 standard. | ISO 32000-2 | iso32000_2_sec9#x1.x29 |
Questa ricetta mostra come NextPDF esegue il rendering di un sottoinsieme supportato di HTML e CSS. Non dichiara il supporto completo di HTML o CSS; lo stato verificato per ciascun modulo è riportato nella matrice di supporto CSS.
Contesto commerciale
Sezione intitolata “Contesto commerciale”Non applicabile.