Skip to content

Funciones avanzadas

Más allá del renderizado básico de HTML a PDF, el paquete Artisan proporciona utilidades para fusionar documentos, inyectar estilos globales, capturar capturas de pantalla y ajustar el comportamiento de Chrome.

Fusión de PDFs

La clase PdfMerger combina múltiples fuentes HTML en un solo documento PDF. Cada fuente se renderiza como una sección separada y los resultados se concatenan en orden.

php
use Yeeefang\TcpdfNext\Artisan\PdfMerger;
use Yeeefang\TcpdfNext\Artisan\RenderOptions;

$merger = PdfMerger::create();

$merger
    ->addHtml('<h1>Cover Page</h1><p>Annual Report 2026</p>')
    ->addFile('/templates/chapter-1.html')
    ->addFile('/templates/chapter-2.html')
    ->addUrl('https://charts.example.com/annual-summary')
    ->addHtml('<h1>Appendix</h1><p>Supporting data tables.</p>');

$merger->save('/reports/annual-2026.pdf');

Opciones por sección

Cada sección puede tener su propio RenderOptions. Por ejemplo, una portada en landscape y capítulos en portrait.

php
$coverOptions = RenderOptions::create()
    ->setPageSize('A4')
    ->setLandscape(true)
    ->setPrintBackground(true);

$chapterOptions = RenderOptions::create()
    ->setPageSize('A4')
    ->setLandscape(false)
    ->setDisplayHeaderFooter(true)
    ->setFooterTemplate('
        <div style="font-size: 8px; text-align: center; width: 100%; color: #888;">
            Page <span class="pageNumber"></span>
        </div>
    ');

PdfMerger::create()
    ->addHtml('<h1>Cover</h1>', options: $coverOptions)
    ->addFile('/templates/chapter-1.html', options: $chapterOptions)
    ->addFile('/templates/chapter-2.html', options: $chapterOptions)
    ->save('/reports/merged.pdf');

Inyección de CSS

La clase StyleInjector antepone reglas CSS a la página renderizada. Esto es útil para aplicar una hoja de estilos de marca global a plantillas que no controlas.

php
use Yeeefang\TcpdfNext\Artisan\HtmlRenderer;
use Yeeefang\TcpdfNext\Artisan\StyleInjector;

$injector = StyleInjector::create()
    ->addCss('
        body {
            font-family: "Inter", "Noto Sans TC", sans-serif;
            font-size: 11pt;
            line-height: 1.6;
            color: #333;
        }
        h1 { color: #1a237e; }
    ')
    ->addCssFile('/styles/brand.css');

HtmlRenderer::create()
    ->loadFile('/templates/report.html')
    ->withStyleInjector($injector)
    ->save('/output/branded-report.pdf');

Múltiples capas de estilos

Los estilos se inyectan en el orden en que se agregan. Las reglas posteriores sobrescriben a las anteriores, siguiendo la especificidad CSS estándar.

php
$injector = StyleInjector::create()
    ->addCssFile('/styles/reset.css')
    ->addCssFile('/styles/brand.css')
    ->addCss('table { page-break-inside: avoid; }');  // overrides

Capturas de pantalla

La clase ScreenshotCapture renderiza HTML a formatos de imagen en lugar de PDF. Útil para generar miniaturas, previsualizaciones para redes sociales o testing de regresión visual.

php
use Yeeefang\TcpdfNext\Artisan\ScreenshotCapture;

// Captura de pantalla completa como PNG
ScreenshotCapture::create()
    ->loadHtml('<h1>Preview</h1><p>This will be a PNG image.</p>')
    ->fullPage(true)
    ->format('png')
    ->save('/output/preview.png');

JPEG con calidad

php
ScreenshotCapture::create()
    ->loadUrl('https://example.com/dashboard')
    ->format('jpeg')
    ->quality(85)
    ->save('/output/dashboard.jpg');

Configuración del viewport

php
ScreenshotCapture::create()
    ->loadFile('/templates/email.html')
    ->viewport(width: 1200, height: 800)
    ->deviceScaleFactor(2)  // retina
    ->fullPage(false)
    ->save('/output/email-preview.png');

Configuración de Chrome

Ruta de binario personalizada

Artisan auto-detecta Chrome en rutas comunes del SO. Sobrescribe con chromePath.

php
use Yeeefang\TcpdfNext\Artisan\HtmlRenderer;

$renderer = HtmlRenderer::create(
    chromePath: '/opt/google/chrome/chrome',
);

O establece la variable de entorno CHROME_PATH globalmente.

Flags de modo headless

Artisan pasa --headless=new por defecto (Chrome 112+). Puedes agregar flags adicionales para entornos específicos.

php
$renderer = HtmlRenderer::create(
    chromeFlags: [
        '--no-sandbox',            // required in Docker
        '--disable-gpu',           // recommended in Docker
        '--disable-dev-shm-usage', // avoid /dev/shm issues
        '--font-render-hinting=none',
    ],
);

Connection pooling

Para escenarios de alto rendimiento, reutiliza una sola instancia de Chrome entre múltiples renderizados. Esto elimina el costo de arranque (aproximadamente 300--500 ms) para cada renderizado subsiguiente.

php
use Yeeefang\TcpdfNext\Artisan\ChromeBridge;
use Yeeefang\TcpdfNext\Artisan\HtmlRenderer;

// Crear un bridge persistente
$bridge = ChromeBridge::create(chromePath: '/usr/bin/chromium');

// Reutilizar entre múltiples renderizados
foreach ($reports as $report) {
    HtmlRenderer::createWithBridge($bridge)
        ->loadHtml($report->html)
        ->save("/output/{$report->id}.pdf");
}

// Cerrar explícitamente cuando se termine
$bridge->close();

Manejo de errores

Todas las excepciones de Artisan extienden Yeeefang\TcpdfNext\Artisan\Exceptions\ArtisanException.

php
use Yeeefang\TcpdfNext\Artisan\Exceptions\RenderException;
use Yeeefang\TcpdfNext\Artisan\Exceptions\ChromeNotFoundException;
use Yeeefang\TcpdfNext\Artisan\Exceptions\TimeoutException;

try {
    HtmlRenderer::create()->loadUrl($url)->save($path);
} catch (ChromeNotFoundException $e) {
    // Install Chrome or set CHROME_PATH
} catch (TimeoutException $e) {
    // Increase timeout or check network
} catch (RenderException $e) {
    // Inspect $e->getMessage() for details
}
ExcepciónCausa común
ChromeNotFoundExceptionChrome no instalado, CHROME_PATH incorrecto
TimeoutExceptionPágina lenta, promesas JS sin resolver, problemas de red
RenderExceptionHTML inválido, crash de Chrome, fallo de escritura en disco

Consejos de rendimiento

  1. Reutilizar instancias de Chrome -- Usa ChromeBridge para operaciones por lotes.
  2. Minimizar JavaScript -- Cuanto menos JS deba ejecutar Chrome, más rápido será el renderizado.
  3. Incluir CSS crítico en línea -- Evita obtener hojas de estilo externas cuando sea posible.
  4. Establecer un timeout ajustado -- Falla rápido en páginas rotas en lugar de bloquear la cola.
  5. Usar setPrintBackground(false) -- Omite el renderizado de fondos cuando no lo necesites.

Próximos pasos

Distribuido bajo la licencia LGPL-3.0-or-later.