Skip to content

고급 기능

기본 HTML-to-PDF 렌더링 외에도 Artisan 패키지는 문서 병합, 전역 스타일 주입, 스크린샷 캡처, Chrome 동작 세부 조정을 위한 유틸리티를 제공합니다.

PDF 병합

PdfMerger 클래스는 여러 HTML 소스를 단일 PDF 문서로 결합합니다. 각 소스는 별도의 섹션으로 렌더링되며 결과는 순서대로 연결됩니다.

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

섹션별 옵션

각 섹션은 자체 RenderOptions를 가질 수 있습니다. 예를 들어, 표지는 가로 방향이고 챕터는 세로 방향입니다.

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

CSS 주입

StyleInjector 클래스는 렌더링된 페이지에 CSS 규칙을 삽입합니다. 이는 제어할 수 없는 템플릿에 전역 브랜드 스타일시트를 적용할 때 유용합니다.

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

다중 스타일 레이어

스타일은 추가된 순서대로 주입됩니다. 나중 규칙이 이전 규칙을 재정의하며, 표준 CSS 명시도를 따릅니다.

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

스크린샷

ScreenshotCapture 클래스는 PDF 대신 이미지 형식으로 HTML을 렌더링합니다. 썸네일, 소셜 미디어 미리보기 또는 비주얼 회귀 테스트 생성에 유용합니다.

php
use Yeeefang\TcpdfNext\Artisan\ScreenshotCapture;

// 전체 페이지 스크린샷을 PNG로
ScreenshotCapture::create()
    ->loadHtml('<h1>Preview</h1><p>This will be a PNG image.</p>')
    ->fullPage(true)
    ->format('png')
    ->save('/output/preview.png');

품질이 지정된 JPEG

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

뷰포트 구성

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

Chrome 구성

사용자 정의 바이너리 경로

Artisan은 일반적인 OS 경로에서 Chrome을 자동 감지합니다. chromePath로 재정의합니다.

php
use Yeeefang\TcpdfNext\Artisan\HtmlRenderer;

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

또는 CHROME_PATH 환경 변수를 전역으로 설정합니다.

헤드리스 모드 플래그

Artisan은 기본적으로 --headless=new를 전달합니다(Chrome 112+). 특정 환경에 대한 추가 플래그를 추가할 수 있습니다.

php
$renderer = HtmlRenderer::create(
    chromeFlags: [
        '--no-sandbox',            // Docker에서 필수
        '--disable-gpu',           // Docker에서 권장
        '--disable-dev-shm-usage', // /dev/shm 문제 방지
        '--font-render-hinting=none',
    ],
);

연결 풀링

고처리량 시나리오에서는 여러 렌더링 간에 단일 Chrome 인스턴스를 재사용합니다. 이는 각 후속 렌더링에 대한 시작 비용(약 300--500ms)을 제거합니다.

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

// 영구 브리지 생성
$bridge = ChromeBridge::create(chromePath: '/usr/bin/chromium');

// 여러 렌더링 간에 재사용
foreach ($reports as $report) {
    HtmlRenderer::createWithBridge($bridge)
        ->loadHtml($report->html)
        ->save("/output/{$report->id}.pdf");
}

// 완료 시 명시적으로 닫기
$bridge->close();

오류 처리

모든 Artisan 예외는 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) {
    // Chrome 설치 또는 CHROME_PATH 설정
} catch (TimeoutException $e) {
    // 타임아웃 증가 또는 네트워크 확인
} catch (RenderException $e) {
    // $e->getMessage()로 상세 정보 확인
}
예외일반적인 원인
ChromeNotFoundExceptionChrome 미설치, CHROME_PATH 잘못됨
TimeoutException느린 페이지, 해결되지 않은 JS 프로미스, 네트워크 문제
RenderException잘못된 HTML, Chrome 충돌, 디스크 쓰기 실패

성능 팁

  1. Chrome 인스턴스 재사용 -- 배치 작업에 ChromeBridge를 사용합니다.
  2. JavaScript 최소화 -- Chrome이 실행해야 할 JS가 적을수록 렌더링이 빨라집니다.
  3. 크리티컬 CSS 인라인화 -- 가능한 경우 외부 스타일시트 가져오기를 피합니다.
  4. 짧은 타임아웃 설정 -- 큐를 차단하는 것보다 깨진 페이지에서 빠르게 실패합니다.
  5. setPrintBackground(false) 사용 -- 배경 렌더링이 필요하지 않을 때 건너뜁니다.

다음 단계

LGPL-3.0-or-later 라이선스로 배포됩니다.