Skip to content

高级功能

本页涵盖 Artisan 包的高级类:PDF 合并、样式注入、截图捕获,以及 Chrome 进程管理与错误处理。

PDF 合并(PdfMerger)

PdfMerger 将多份 PDF 文件合并为单一文件,支持文件路径与二进制字符串两种输入方式:

php
use Yeeefang\TcpdfNext\Artisan\PdfMerger;

PdfMerger::create()
    ->add('/path/to/cover.pdf')
    ->add('/path/to/chapter1.pdf')
    ->add('/path/to/chapter2.pdf')
    ->save('/path/to/merged.pdf');

从二进制字符串合并

搭配 HtmlRenderer::toString() 使用,可在内存中完成渲染与合并,无需写入临时文件:

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

$renderer = HtmlRenderer::create();

$cover   = $renderer->loadHtml($coverHtml)->toString();
$content = $renderer->loadHtml($contentHtml)->toString();

PdfMerger::create()
    ->addBinary($cover)
    ->addBinary($content)
    ->save('/path/to/final.pdf');

样式注入(StyleInjector)

StyleInjector 在 Chrome 渲染之前,将额外的 CSS 注入到 HTML 中。适用于在不修改模板的情况下覆盖样式:

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

$injector = StyleInjector::create()
    ->add('body { font-family: "Noto Sans TC", sans-serif; }')
    ->add('@page { size: A4 landscape; }')
    ->addFile('/path/to/print-overrides.css');

HtmlRenderer::create()
    ->withStyleInjector($injector)
    ->loadUrl('https://app.example.com/dashboard')
    ->save('/tmp/dashboard.pdf');

TIP

注入的样式会被包裹在 <style> 标签中并插入到 <head> 的最末端,因此在层叠顺序中具有最高优先权。

截图捕获(ScreenshotCapture)

ScreenshotCapture 将 HTML 渲染为图片而非 PDF,支持 PNG 与 JPEG 格式:

php
use Yeeefang\TcpdfNext\Artisan\ScreenshotCapture;

// 全页截图
ScreenshotCapture::create()
    ->loadUrl('https://example.com')
    ->fullPage()
    ->format('png')
    ->save('/tmp/screenshot.png');

// 指定视窗大小与 JPEG 品质
ScreenshotCapture::create()
    ->loadHtml($html)
    ->viewport(width: 1280, height: 720)
    ->format('jpeg')
    ->quality(85)
    ->save('/tmp/preview.jpg');

裁切特定区域

通过 clip() 只捕获页面中的特定矩形区域:

php
ScreenshotCapture::create()
    ->loadUrl('https://example.com')
    ->clip(x: 0, y: 0, width: 800, height: 600)
    ->save('/tmp/cropped.png');

Chrome 进程设置

自定义 Chrome 路径

php
use Yeeefang\TcpdfNext\Artisan\HtmlRenderer;

$renderer = HtmlRenderer::create(
    chromePath: '/usr/bin/google-chrome-stable',
);

额外启动参数

通过 chromeArgs() 传递额外的 Chrome 命令行参数:

php
$renderer = HtmlRenderer::create()
    ->chromeArgs([
        '--no-sandbox',
        '--disable-dev-shm-usage',
        '--disable-gpu',
        '--font-render-hinting=none',
    ]);

进程复用

默认情况下,每次渲染都会启动并关闭一个 Chrome 进程。如果需要批量渲染多份 PDF,可以复用同一个进程以提升性能:

php
$renderer = HtmlRenderer::create()->persistent();

foreach ($invoices as $invoice) {
    $renderer->loadHtml($invoice->html)
        ->save("/tmp/invoice-{$invoice->id}.pdf");
}

$renderer->close(); // 手动关闭 Chrome 进程

性能建议

策略说明
复用进程使用 persistent() 避免重复启动 Chrome
避免 waitForTimeout改用 waitForSelector() 以缩短等待时间
缩小 HTML移除不必要的空白与注释
本地资源将字体与图片放在本地,避免网络延迟
停用动画注入 * { animation: none !important; }

错误处理

Artisan 定义了明确的异常类,方便进行精确的错误处理:

php
use Yeeefang\TcpdfNext\Artisan\Exceptions\ChromeNotFoundException;
use Yeeefang\TcpdfNext\Artisan\Exceptions\RenderTimeoutException;
use Yeeefang\TcpdfNext\Artisan\Exceptions\CdpException;

try {
    HtmlRenderer::create()
        ->loadHtml($html)
        ->save('/tmp/output.pdf');
} catch (ChromeNotFoundException $e) {
    // Chrome 可执行文件不存在或路径错误
} catch (RenderTimeoutException $e) {
    // 渲染超过超时上限
} catch (CdpException $e) {
    // CDP 通信错误(如连接中断、协议错误)
}
异常触发时机
ChromeNotFoundException找不到 Chrome 可执行文件
RenderTimeoutException渲染超时
CdpExceptionCDP WebSocket 通信失败
FileNotFoundExceptionloadFile() 指定的文件不存在
MergeExceptionPDF 合并过程中发生错误

以 LGPL-3.0-or-later 许可证发布。