Renderizar HTML en una página PDF
De un vistazo
Sección titulada «De un vistazo»Esta recipe convierte un fragmento de HTML y CSS en contenido de página PDF con un solo método, writeHtml(). Basta con proporcionar el marcado para renderizar una página con formato. La versión completa y ejecutable de este código está en examples/08-html-basic.php. Se pueden seguir los pasos siguientes o copiar el ejemplo directamente.
NextPDF lee el HTML en un solo paso y transmite el resultado directamente a la página. Es una pipeline de transmisión de un solo paso. No es necesario comprender ese modelo para usar la recipe, pero conviene tenerlo presente porque condiciona algunas de las reglas que aparecen más adelante en esta página.
Instalación
Sección titulada «Instalación»composer require nextpdf/core:^3Ese comando instala el paquete nextpdf/core. Los ejemplos de esta página se ejecutan en PHP 8.4, y el runtime admitido es >=8.4 <9.0.
Panorama conceptual
Sección titulada «Panorama conceptual»writeHtml() toma una cadena de HTML y la dibuja en la página actual, a partir de la posición actual del cursor. Esto es lo que ocurre por dentro, paso a paso. Primero, el motor recorre el HTML una vez y lo divide en una lista de tokens (HtmlTokenizer). Luego recorre esa lista de izquierda a derecha (HtmlParser). Por cada elemento, escribe en un búfer las instrucciones de dibujo PDF correspondientes: los operadores del flujo de contenido. El motor nunca construye ni conserva en memoria un árbol de los elementos entre llamadas. Es un diseño deliberado, el modelo de transmisión de un solo paso, y queda registrado en la ADR-001.
Cada elemento de bloque admitido se convierte en una caja de maquetación, y cada secuencia de texto se convierte en un operador de mostrado de texto. Los estilos de los atributos style en línea y de un bloque <style> se resuelven mediante la cascada de CSS: las reglas estándar que deciden qué estilo gana cuando se aplica más de uno. El ajuste de línea, la alineación y el espaciado del texto siguen el modelo de CSS Text, que rige cómo el texto de origen se convierte en texto con formato y con líneas ajustadas (W3C CSS Text Level 3).
Si no se elige una fuente, el texto del cuerpo usa una tipografía predeterminada. Esa predeterminada es una fuente Type 1 estándar: una de las 14 fuentes estándar nombradas en ISO 32000-2. La predeterminada solo cambia cuando se registra y selecciona una fuente propia, o cuando un perfil de conformidad obliga a NextPDF a incrustar una sustituta.
Conviene fijar una expectativa desde el principio: NextPDF admite un subconjunto de HTML y CSS, no la totalidad de ninguno de los dos. Esta recipe cubre ese subconjunto admitido y no afirma admitir HTML completo ni CSS completo. Para conocer el estado exacto y verificado de cada módulo, consulta la matriz de compatibilidad de CSS.
Superficie de la API
Sección titulada «Superficie de la API»La firma del método es writeHtml(string $html): static. Está declarado en la interfaz NextPDF\Contracts\PdfDocumentInterface e implementado en NextPDF\Core\Concerns\HasTextOutput. Renderiza en la página actual y crea una automáticamente si todavía no existe ninguna. La tabla PHPDoc completa del método se genera a partir del código fuente.
Ejemplo de código — Inicio rápido
Sección titulada «Ejemplo de código — Inicio rápido»<?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');Ejemplo de código — Producción
Sección titulada «Ejemplo de código — Producción»Este es el ejemplo completo y autónomo, y es el que ejecuta el arnés de pruebas. Refleja examples/08-html-basic.php. En lugar de fijar en el código una ruta de salida, escribe en la ubicación que proporciona el arnés, para que el arnés de reproducibilidad pueda ejecutar el script dos veces y comparar los resultados.
<?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 esperado:
Wrote render-html-to-pdf.pdfCasos límite y trampas
Sección titulada «Casos límite y trampas»- Avance del cursor.
writeHtml()avanza el cursor hasta el final del contenido renderizado. Uncell()posterior o un segundowriteHtml()continúa desde ahí, no desde la parte superior de la página. - Todavía no hay página. Si no existe ninguna página,
writeHtml()añade una antes de renderizar. Llama aaddPage()de forma explícita cuando necesites fijar primero un tamaño de página concreto. - Límites de elementos y de anidamiento. El motor de transmisión impone límites de
50,000elementos y de 100 niveles de anidamiento (ADR-001). Un documento que los supera se rechaza en lugar de truncarse de forma silenciosa. - Marcado no admitido. Los elementos y propiedades fuera del subconjunto admitido se ignoran o se sustituyen por una alternativa; no generan errores. Confirma la cobertura en la matriz de compatibilidad de CSS antes de depender de una propiedad.
- Recursos externos. Las imágenes y hojas de estilo remotas se rigen por la política de recursos externos; la política predeterminada no descarga URL remotas arbitrarias.
Rendimiento
Sección titulada «Rendimiento»Dado que la tokenización y el renderizado ocurren en un solo paso sobre la entrada, el costo crece de forma lineal con el número de tokens, es decir, O(n). El presupuesto predeterminado para esta recipe es wall_ms: 1500, peak_mb: 96. Como el motor transmite la salida y no mantiene ningún DOM en memoria, el pico de memoria sigue el tamaño del búfer del flujo de contenido y la pila de estilos activa, no el tamaño del documento completo.
Extracto de la matriz de compatibilidad de CSS (solo filas verificadas)
Sección titulada «Extracto de la matriz de compatibilidad de CSS (solo filas verificadas)»Aquí solo aparecen las filas con estado Verificado en la matriz de compatibilidad de CSS con auditoría de veracidad. «Verificado» significa una implementación en src/Html/ junto con un conjunto dedicado y sustancial de fixtures que pasa de forma determinista bajo el perfil estructural.
| Módulo de W3C | Nivel | Estado | Evidencia |
|---|---|---|---|
CSS Flexible Box Layout (css_flexbox_1) | 1 | Verificado | src/Html/Flex/, tests/Unit/Html/Flex/ |
CSS Grid Layout (css_grid_1) | 1 | Verificado | src/Html/Grid/, corpus WPT |
CSS Cascading and Inheritance (css_cascade_3) | 3 | Verificado | src/Html/Cascade/, tests/Unit/Html/Cascade/ |
CSS Table (css_tables_3) | 3 | Verificado | src/Html/Table/, fixtures de tablas + PDF de referencia |
CSS Fonts (css_fonts_4) | 4 | Verificado | src/Html/FontFace/, tests/Unit/Html/FontFace/ |
Propiedades como text-align, text-indent y color están calificadas como «Reivindicado» en la matriz (implementadas, sin fixture de módulo dedicado), así que no se listan aquí como Verificadas a propósito.
Restricciones de la transmisión de un solo paso (ADR-001)
Sección titulada «Restricciones de la transmisión de un solo paso (ADR-001)»El motor de HTML no conserva ningún DOM. El estado es un cursor escalar más una pila de estilos push/pop; los nodos de texto que solo contienen espacios en blanco se descartan en la tokenización. Como consecuencia, un elemento posterior no puede reestilizar uno anterior, y los selectores que necesitan el contexto del árbol completo (por ejemplo, los casos complejos de :has()) están restringidos según la ADR-006. Conviene planificar una maquetación que dependa solo del orden del documento.
Contratos de capa (ADR-010)
Sección titulada «Contratos de capa (ADR-010)»El análisis, la maquetación y el pintado son capas separadas. El analizador no emite operadores de pintado en bruto, y el dispatch de maquetación no analiza CSS; cruzar esos límites es la deuda de acoplamiento que la ADR-010 prohíbe. Para los autores de recipes, esto significa que el punto de entrada público es writeHtml(): no recurrir a los componentes internos del analizador.
Presupuesto de memoria para documentos grandes
Sección titulada «Presupuesto de memoria para documentos grandes»Según la ADR-020, los contextos de formato con ámbito de contenedor (flex, tabla) pueden construir un subárbol efímero, acotado a 5,000 nodos por contexto, 20 niveles de profundidad, con un techo de memoria activa de 50 MB en los contextos vivos y 10 niveles de anidamiento. Fuera de esos contextos, el modelo de transmisión no mantiene ningún árbol. Mantener cada tabla y contenedor flex individual dentro del límite de nodos permite un uso de memoria predecible.
Notas de seguridad
Sección titulada «Notas de seguridad»Tratar la entrada HTML como no confiable. NextPDF no ejecuta scripts, y la política de recursos externos predeterminada no descarga URL remotas arbitrarias, así que el motor en sí es conservador. Aun así, validar o sanear cualquier HTML que se ensamble a partir de la entrada del usuario antes de renderizarlo. Los límites de elementos y de anidamiento también ofrecen protección: acotan cuánto trabajo puede exigir un documento hostil o malformado.
Conformidad
Sección titulada «Conformidad»| Declaración | Especificación | Cláusula | reference_id |
|---|---|---|---|
| CSS Text controla la conversión del texto de origen en texto con formato y con líneas ajustadas. | W3C CSS Text Level 3 | css_text_3#x1.x2.p4 | |
| La tipografía predeterminada del cuerpo se resuelve a una fuente Type 1 estándar. | ISO 32000-2 | iso32000_2_sec9#x1.x29 |
Esta recipe muestra cómo NextPDF renderiza un subconjunto admitido de HTML y CSS. No afirma admitir HTML completo ni CSS completo; el estado verificado por módulo está en la matriz de compatibilidad de CSS.
Contexto comercial
Sección titulada «Contexto comercial»No aplica.