Rendre du HTML dans une page PDF
Cette recette transforme un fragment de HTML et de CSS en contenu de page PDF avec une seule méthode, writeHtml(). Passe-lui du balisage, et elle rend une page mise en forme. La version complète et exécutable de ce code se trouve dans examples/08-html-basic.php. Suis les étapes ci-dessous, ou copie directement l’exemple.
NextPDF lit ton HTML en une seule passe et diffuse le résultat directement dans la page. C’est un pipeline de streaming en une seule passe. Tu n’as pas besoin de comprendre ce modèle pour utiliser la recette, mais mieux vaut le garder en tête, car il explique certaines règles plus bas sur cette page.
Installation
Section intitulée « Installation »composer require nextpdf/core:^3Cette commande installe le package nextpdf/core. Les exemples de cette page tournent sur PHP 8.4, et l’environnement d’exécution pris en charge est >=8.4 <9.0.
Vue d’ensemble conceptuelle
Section intitulée « Vue d’ensemble conceptuelle »writeHtml() prend une chaîne de HTML et la dessine dans la page courante, à partir de la position actuelle du curseur. Voici ce qui se passe à l’intérieur, étape par étape. D’abord, le moteur parcourt ton HTML une fois et le découpe en une liste de tokens (HtmlTokenizer). Ensuite, il parcourt cette liste de gauche à droite (HtmlParser). Pour chaque élément, il écrit les instructions de dessin PDF correspondantes — des opérateurs de flux de contenu — dans un tampon. Le moteur ne construit ni ne conserve jamais en mémoire l’arborescence de tes éléments entre les appels. Cette conception délibérée, le modèle de streaming en une seule passe, est consignée dans l’ADR-001.
Chaque élément de bloc pris en charge devient une boîte de mise en page, et chaque suite de texte devient un opérateur d’affichage de texte. Les styles issus des attributs style en ligne et d’un bloc <style> se résolvent à travers la cascade CSS — les règles standard qui décident quel style l’emporte quand plusieurs s’appliquent. Le retour à la ligne du texte, l’alignement et l’espacement suivent le modèle CSS Text, qui régit la façon dont le texte source devient un texte mis en forme et coupé en lignes (W3C CSS Text Level 3).
Si tu ne choisis pas de police, le texte courant utilise une police par défaut. Cette police par défaut est une police Type 1 standard — l’une des 14 polices standard nommées dans ISO 32000-2. Elle ne change que lorsque tu enregistres et sélectionnes ta propre police, ou lorsqu’un profil de conformité oblige NextPDF à intégrer une police de substitution.
Garde ce point en tête dès le départ : NextPDF prend en charge un sous-ensemble de HTML et de CSS, pas la totalité de l’un ni de l’autre. Cette recette couvre ce sous-ensemble pris en charge et ne prétend pas à une prise en charge complète de HTML ni de CSS. Pour le statut exact et vérifié de chaque module, consulte la matrice de prise en charge CSS.
Surface d’API
Section intitulée « Surface d’API »La signature de la méthode est writeHtml(string $html): static. Elle est déclarée sur l’interface NextPDF\Contracts\PdfDocumentInterface et implémentée dans NextPDF\Core\Concerns\HasTextOutput. Elle rend dans la page courante et en crée une pour toi si aucune page n’existe encore. La documentation PHPDoc complète de la méthode est générée à partir du code source.
Exemple de code — Démarrage rapide
Section intitulée « Exemple de code — Démarrage rapide »<?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');Exemple de code — Production
Section intitulée « Exemple de code — Production »C’est l’exemple complet et autonome, et c’est celui qu’exécute le harnais de test. Il reflète examples/08-html-basic.php. Au lieu de coder en dur un chemin de sortie, il écrit à l’emplacement fourni par le harnais, ce qui permet au harnais de reproductibilité d’exécuter le script deux fois et de comparer les résultats.
<?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";Sortie standard attendue :
Wrote render-html-to-pdf.pdfCas limites & pièges
Section intitulée « Cas limites & pièges »- Passage du curseur.
writeHtml()avance le curseur jusqu’à la fin du contenu rendu. Uncell()suivant ou un secondwriteHtml()continue à partir de là, pas depuis le haut de la page. - Pas encore de page. Si aucune page n’existe,
writeHtml()en ajoute une avant le rendu. AppelleaddPage()explicitement quand tu dois d’abord fixer une taille de page précise. - Limites d’éléments et d’imbrication. Le moteur de streaming impose une limite de
50,000éléments et de 100 niveaux d’imbrication (ADR-001). Un document qui les dépasse est rejeté, plutôt que tronqué silencieusement. - Balisage non pris en charge. Les éléments et propriétés hors du sous-ensemble pris en charge sont ignorés ou utilisent une valeur de repli ; ils ne déclenchent pas d’erreur. Confirme la couverture dans la matrice de prise en charge CSS avant de compter sur une propriété.
- Ressources externes. Les images et feuilles de style distantes sont régies par la politique de ressources externes ; la politique par défaut ne récupère pas d’URL distantes arbitraires.
Performance
Section intitulée « Performance »Comme la tokenisation et le rendu se font en une seule passe sur ton entrée, le coût croît linéairement avec le nombre de tokens — c’est-à-dire en O(n). Le budget par défaut pour cette recette est wall_ms: 1500, peak_mb: 96. Comme le moteur diffuse la sortie et ne garde aucun DOM en mémoire, le pic de mémoire suit la taille du tampon de flux de contenu et de la pile de styles active, pas celle du document entier.
Extrait de la matrice de prise en charge CSS (lignes vérifiées uniquement)
Section intitulée « Extrait de la matrice de prise en charge CSS (lignes vérifiées uniquement) »Seules les lignes marquées Verified dans la matrice de prise en charge CSS et auditées pour exactitude apparaissent ici. « Verified » signifie qu’il existe une implémentation dans src/Html/, ainsi qu’une suite de fixtures dédiée et substantielle qui passe de façon déterministe sous le profil structurel.
| Module W3C | Niveau | Statut | Preuve |
|---|---|---|---|
CSS Flexible Box Layout (css_flexbox_1) | 1 | Verified | src/Html/Flex/, tests/Unit/Html/Flex/ |
CSS Grid Layout (css_grid_1) | 1 | Verified | src/Html/Grid/, corpus WPT |
CSS Cascading and Inheritance (css_cascade_3) | 3 | Verified | src/Html/Cascade/, tests/Unit/Html/Cascade/ |
CSS Table (css_tables_3) | 3 | Verified | src/Html/Table/, fixtures de tables + PDF de référence |
CSS Fonts (css_fonts_4) | 4 | Verified | src/Html/FontFace/, tests/Unit/Html/FontFace/ |
Des propriétés telles que text-align, text-indent et color sont marquées « Claimed » dans la matrice (implémentées, sans fixture de module dédiée) ; elles ne sont donc volontairement pas listées comme Verified ici.
Contraintes du streaming en une seule passe (ADR-001)
Section intitulée « Contraintes du streaming en une seule passe (ADR-001) »Le moteur HTML ne conserve aucun DOM. Son état se réduit à un curseur scalaire et à une pile de styles push/pop ; les nœuds de texte contenant uniquement des espaces sont écartés au moment de la tokenisation. Conséquence : un élément ultérieur ne peut pas restyler un élément précédent, et les sélecteurs qui ont besoin du contexte de l’arbre complet (par exemple, les cas complexes de :has()) sont contraints selon l’ADR-006. Conçois une mise en page qui ne dépend que de l’ordre du document.
Contrats de couche (ADR-010)
Section intitulée « Contrats de couche (ADR-010) »L’analyse, la mise en page et la peinture sont des couches distinctes. L’analyseur n’émet pas d’opérateurs de peinture bruts, et la couche de mise en page n’analyse pas le CSS ; franchir ces frontières crée précisément la dette de couplage que l’ADR-010 interdit. Pour les auteurs de recettes, cela signifie que le point d’entrée public est writeHtml() — n’accède pas aux rouages internes de l’analyseur.
Budget mémoire pour les gros documents
Section intitulée « Budget mémoire pour les gros documents »Selon l’ADR-020, les contextes de mise en forme à portée de conteneur (flex, table) peuvent construire un sous-arbre éphémère, limité à 5,000 nœuds par contexte et à 20 niveaux de profondeur, avec un plafond de mémoire active de 50 Mo sur l’ensemble des contextes vivants et 10 niveaux d’imbrication. En dehors de ces contextes, le modèle de streaming ne garde aucun arbre. Garde chaque table et conteneur flex sous la limite de nœuds pour conserver une mémoire prévisible.
Notes de sécurité
Section intitulée « Notes de sécurité »Traite l’entrée HTML comme non fiable. NextPDF n’exécute pas de scripts, et la politique de ressources externes par défaut ne récupère pas d’URL distantes arbitraires ; le moteur lui-même reste donc prudent. Malgré tout, valide ou assainis tout HTML que tu assembles à partir d’une entrée utilisateur avant de le rendre. Les limites d’éléments et d’imbrication te protègent aussi : elles bornent la quantité de travail qu’un document hostile ou malformé peut exiger.
Conformité
Section intitulée « Conformité »| Énoncé | Spécification | Clause | reference_id |
|---|---|---|---|
| CSS Text régit la transformation du texte source en texte mis en forme et coupé en lignes. | W3C CSS Text Level 3 | css_text_3#x1.x2.p4 | |
| La fonte de corps par défaut se résout en une police Type 1 standard. | ISO 32000-2 | iso32000_2_sec9#x1.x29 |
Cette recette montre comment NextPDF rend un sous-ensemble pris en charge de HTML et de CSS. Elle n’affirme pas une prise en charge complète de HTML ni de CSS ; le statut vérifié par module se trouve dans la matrice de prise en charge CSS.
Contexte commercial
Section intitulée « Contexte commercial »Non applicable.