Продвинутые функции
Помимо базового рендеринга HTML-в-PDF, пакет Artisan предоставляет утилиты для объединения документов, внедрения глобальных стилей, захвата скриншотов и тонкой настройки поведения Chrome.
Объединение PDF
Класс PdfMerger объединяет несколько HTML-источников в один PDF-документ. Каждый источник рендерится как отдельная секция, и результаты конкатенируются по порядку.
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');Опции для каждой секции
Каждая секция может иметь собственные RenderOptions. Например, обложка в альбомной ориентации, а главы в портретной.
$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');Внедрение CSS
Класс StyleInjector подставляет CSS-правила перед отрендеренной страницей. Это полезно для применения глобальной брендовой таблицы стилей к шаблонам, которые вы не контролируете.
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');Множественные слои стилей
Стили внедряются в порядке добавления. Более поздние правила переопределяют более ранние, следуя стандартной специфичности CSS.
$injector = StyleInjector::create()
->addCssFile('/styles/reset.css')
->addCssFile('/styles/brand.css')
->addCss('table { page-break-inside: avoid; }'); // overridesСкриншоты
Класс ScreenshotCapture рендерит HTML в форматы изображений вместо PDF. Полезно для генерации миниатюр, превью для социальных сетей или визуального регрессионного тестирования.
use Yeeefang\TcpdfNext\Artisan\ScreenshotCapture;
// Full page screenshot as PNG
ScreenshotCapture::create()
->loadHtml('<h1>Preview</h1><p>This will be a PNG image.</p>')
->fullPage(true)
->format('png')
->save('/output/preview.png');JPEG с настройкой качества
ScreenshotCapture::create()
->loadUrl('https://example.com/dashboard')
->format('jpeg')
->quality(85)
->save('/output/dashboard.jpg');Настройка вьюпорта
ScreenshotCapture::create()
->loadFile('/templates/email.html')
->viewport(width: 1200, height: 800)
->deviceScaleFactor(2) // retina
->fullPage(false)
->save('/output/email-preview.png');Конфигурация Chrome
Пользовательский путь к бинарному файлу
Artisan автоматически обнаруживает Chrome по стандартным путям ОС. Переопределите с помощью chromePath.
use Yeeefang\TcpdfNext\Artisan\HtmlRenderer;
$renderer = HtmlRenderer::create(
chromePath: '/opt/google/chrome/chrome',
);Или установите переменную окружения CHROME_PATH глобально.
Флаги headless-режима
Artisan передаёт --headless=new по умолчанию (Chrome 112+). Вы можете добавить дополнительные флаги для специфических окружений.
$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',
],
);Пул соединений
Для сценариев высокой пропускной способности повторно используйте один экземпляр Chrome для нескольких рендеров. Это устраняет стоимость запуска (приблизительно 300--500 мс) для каждого последующего рендера.
use Yeeefang\TcpdfNext\Artisan\ChromeBridge;
use Yeeefang\TcpdfNext\Artisan\HtmlRenderer;
// Create a persistent bridge
$bridge = ChromeBridge::create(chromePath: '/usr/bin/chromium');
// Reuse across multiple renders
foreach ($reports as $report) {
HtmlRenderer::createWithBridge($bridge)
->loadHtml($report->html)
->save("/output/{$report->id}.pdf");
}
// Explicitly close when done
$bridge->close();Обработка ошибок
Все исключения Artisan наследуют Yeeefang\TcpdfNext\Artisan\Exceptions\ArtisanException.
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
}| Исключение | Типичная причина |
|---|---|
ChromeNotFoundException | Chrome не установлен, CHROME_PATH некорректен |
TimeoutException | Медленная страница, неразрешённые JS-промисы, сетевые проблемы |
RenderException | Невалидный HTML, падение Chrome, ошибка записи на диск |
Советы по производительности
- Повторно используйте экземпляры Chrome -- Используйте
ChromeBridgeдля пакетных операций. - Минимизируйте JavaScript -- Чем меньше JS Chrome должен выполнить, тем быстрее рендеринг.
- Встраивайте критический CSS -- Избегайте загрузки внешних таблиц стилей, когда возможно.
- Устанавливайте жёсткий таймаут -- Быстро завершайте на сломанных страницах, а не блокируйте очередь.
- Используйте
setPrintBackground(false)-- Пропускайте рендеринг фона, когда он не нужен.
Далее
- Render Options -- Размер страницы, поля и шаблоны колонтитулов.
- Настройка Docker -- Запуск Artisan в контейнеризованных окружениях.
- Обзор -- Краткое описание пакета и установка.