Skip to content

Tính năng nâng cao

Ngoài render HTML sang PDF cơ bản, package Artisan cung cấp tiện ích cho ghép document, chèn style toàn cục, chụp ảnh màn hình và tinh chỉnh hành vi Chrome.

Ghép PDF

Class PdfMerger kết hợp nhiều nguồn HTML thành một PDF document duy nhất. Mỗi nguồn được render dạng section riêng, và kết quả được nối theo thứ tự.

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');

Option theo section

Mỗi section có thể có RenderOptions riêng. Ví dụ, trang bìa ngang và chương dọc.

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');

Chèn CSS

Class StyleInjector thêm CSS rule trước trang render. Hữu ích để áp dụng stylesheet thương hiệu toàn cục cho template bạn không kiểm soát.

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');

Nhiều lớp Style

Style được chèn theo thứ tự thêm vào. Rule sau ghi đè rule trước, theo CSS specificity chuẩn.

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

Chụp ảnh màn hình

Class ScreenshotCapture render HTML sang định dạng hình ảnh thay vì PDF. Hữu ích cho tạo thumbnail, preview mạng xã hội hoặc visual regression testing.

php
use Yeeefang\TcpdfNext\Artisan\ScreenshotCapture;

// Chụp ảnh toàn trang dạng PNG
ScreenshotCapture::create()
    ->loadHtml('<h1>Preview</h1><p>This will be a PNG image.</p>')
    ->fullPage(true)
    ->format('png')
    ->save('/output/preview.png');

JPEG với chất lượng

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

Cấu hình Viewport

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

Cấu hình Chrome

Đường dẫn Binary tùy chỉnh

Artisan tự phát hiện Chrome trên đường dẫn OS phổ biến. Ghi đè với chromePath.

php
use Yeeefang\TcpdfNext\Artisan\HtmlRenderer;

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

Hoặc đặt biến môi trường CHROME_PATH toàn cục.

Flag Headless Mode

Artisan truyền --headless=new mặc định (Chrome 112+). Bạn có thể thêm flag cho môi trường cụ thể.

php
$renderer = HtmlRenderer::create(
    chromeFlags: [
        '--no-sandbox',            // bắt buộc trong Docker
        '--disable-gpu',           // khuyên dùng trong Docker
        '--disable-dev-shm-usage', // tránh vấn đề /dev/shm
        '--font-render-hinting=none',
    ],
);

Connection Pooling

Cho tình huống throughput cao, tái sử dụng một instance Chrome cho nhiều render. Điều này loại bỏ chi phí khởi động (khoảng 300--500 ms) cho mỗi render tiếp theo.

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

// Tạo bridge persistent
$bridge = ChromeBridge::create(chromePath: '/usr/bin/chromium');

// Tái sử dụng cho nhiều render
foreach ($reports as $report) {
    HtmlRenderer::createWithBridge($bridge)
        ->loadHtml($report->html)
        ->save("/output/{$report->id}.pdf");
}

// Đóng rõ ràng khi hoàn tất
$bridge->close();

Xử lý lỗi

Mọi exception Artisan extend 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) {
    // Cài Chrome hoặc đặt CHROME_PATH
} catch (TimeoutException $e) {
    // Tăng timeout hoặc kiểm tra mạng
} catch (RenderException $e) {
    // Kiểm tra $e->getMessage() để biết chi tiết
}
ExceptionNguyên nhân phổ biến
ChromeNotFoundExceptionChrome chưa cài, CHROME_PATH sai
TimeoutExceptionTrang chậm, JS promise chưa resolve, vấn đề mạng
RenderExceptionHTML không hợp lệ, Chrome crash, lỗi ghi đĩa

Mẹo hiệu suất

  1. Tái sử dụng instance Chrome -- Dùng ChromeBridge cho thao tác batch.
  2. Tối thiểu JavaScript -- JS càng ít Chrome phải thực thi, render càng nhanh.
  3. Inline CSS quan trọng -- Tránh tải stylesheet bên ngoài khi có thể.
  4. Đặt timeout chặt -- Fail nhanh trên trang lỗi thay vì chặn queue.
  5. Dùng setPrintBackground(false) -- Bỏ qua render nền khi không cần.

Bước tiếp theo

Phân phối theo giấy phép LGPL-3.0-or-later.