콘텐츠로 이동

긴 HTML을 여러 페이지로 나누기

자동 페이지 나누기를 사용해 긴 콘텐츠가 여러 페이지에 걸쳐 이어지도록 합니다. 독자가 섹션 사이를 이동할 수 있게 개요를 추가합니다. 이 레시피는 examples/12-bookmarks-and-toc.php를 따릅니다.

Terminal window
composer require nextpdf/core:^3

이 제약 조건은 nextpdf/core 패키지와 일치합니다. 이 예제는 PHP 8.4에서 실행됩니다.

setAutoPageBreak(true, $margin)은 콘텐츠가 아래쪽 여백 임계값을 넘을 때마다 엔진이 새 페이지를 시작하도록 지시합니다. 엔진은 multiCell() 또는 writeHtml()을 통해 작성된 긴 텍스트를 그 경계에서 분할합니다. CSS Fragmentation 모듈(css_break_3)은 지원 매트릭스에서 Verified로 등급이 매겨져 있으며, HTML 파이프라인의 나누기 동작을 뒷받침합니다.

bookmark($title, $level)은 현재 위치를 가리키는 개요 항목을 추가합니다. PDF 개요 항목은 대상과 연결되므로 사용자가 해당 페이지로 바로 이동할 수 있습니다(ISO 32000-2). 엔진은 해당 대상을 항목의 Dest 항목으로 기록합니다(ISO 32000-2). level 인수는 항목을 리더의 사이드바에 있는 계층적 목차 안에 중첩합니다.

파이프라인은 단일 패스를 유지합니다(ADR-001). 페이지 분할은 보존된 레이아웃 트리에서가 아니라 스트림이 출력되는 동안 결정됩니다.

  • setAutoPageBreak(bool $enabled, float $margin = 20): staticNextPDF\Core\Concerns\HasPages.
  • bookmark(string $title, int $level = 0, float $y = -1): staticNextPDF\Core\Concerns\HasNavigation.
  • multiCell(...) / writeHtml(string $html): staticNextPDF\Core\Concerns\HasTextOutput.

전체 PHPDoc 표는 소스에서 생성됩니다.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setAutoPageBreak(true, margin: 25);
$doc->addPage();
$doc->bookmark('Section 1', level: 0);
$doc->setFont('helvetica', '', 11);
for ($i = 1; $i <= 80; $i++) {
$doc->multiCell(0, 7, "Paragraph {$i} of a long flowing document.");
}
$doc->save(__DIR__ . '/out.pdf');

이 예제는 자체적으로 완결되어 있으며 하니스에서 실행할 수 있습니다. 중첩된 개요와 자동 페이지 나누기를 사용해 여러 챕터로 구성된 문서를 만들며, examples/12-bookmarks-and-toc.php를 반영합니다.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Bookmarks and Navigation');
$doc->setPrintHeader(false);
$doc->setPrintFooter(false);
$doc->setAutoPageBreak(true, margin: 25);
$chapters = [
'Chapter 1: Introduction' => ['What is NextPDF?', 'Key Features'],
'Chapter 2: Getting Started' => ['Installation', 'Your First PDF'],
'Chapter 3: Advanced Topics' => ['Worker-safe Architecture', 'Streaming Output'],
];
$body = 'NextPDF is a modern PDF 2.0 library for PHP. This paragraph is '
. 'repeated so the content overflows the page and the engine inserts '
. 'an automatic page break at the bottom-margin threshold.';
foreach ($chapters as $chapter => $sections) {
$doc->addPage();
$doc->bookmark($chapter, level: 0);
$doc->setFont('helvetica', 'B', 18);
$doc->cell(0, 12, $chapter, newLine: true);
$doc->ln(3);
foreach ($sections as $section) {
$doc->bookmark($section, level: 1);
$doc->setFont('helvetica', 'B', 14);
$doc->cell(0, 10, $section, newLine: true);
$doc->setFont('helvetica', '', 11);
for ($i = 0; $i < 12; $i++) {
$doc->multiCell(0, 7, $body);
}
$doc->ln(4);
}
}
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');
$doc->save($out !== false ? $out : __DIR__ . '/paginate-long-html.pdf');
echo "Wrote paginate-long-html.pdf\n";

예상 STDOUT:

Wrote paginate-long-html.pdf
  • 비활성화 후 잊어버리기. 자동 페이지 나누기가 비활성화되어 있으면 엔진은 콘텐츠를 흐르게 하는 대신 아래쪽 여백을 넘는 부분을 잘라냅니다. 긴 콘텐츠를 처리하기 전에 다시 활성화해야 합니다.
  • 분할할 수 없는 콘텐츠. 사용 가능한 페이지 높이보다 큰 단일 블록은 UnsplittableContentException을 발생시킬 수 있습니다. 매우 높은 표 행이나 큰 이미지가 그 원인 중 하나입니다. 소스 콘텐츠를 분할해야 합니다.
  • 콘텐츠 앞에 북마크 지정. 대상이 가리켜야 하는 위치에서 bookmark()를 호출해야 합니다. 원하는 페이지에서 다음에 작성할 제목 바로 앞에 배치합니다.
  • 머리글과 바닥글은 공간을 차지합니다. 인쇄 머리글이나 바닥글은 사용 가능한 콘텐츠 높이를 줄이며, 나누기 임계값은 이를 고려합니다. 예제에서처럼 둘 다 비활성화하면 본문 높이 전체를 사용할 수 있습니다.
  • 개요 중첩. level은 중첩 깊이입니다. level: 1의 자식은 level: 0 부모를 뒤따라야 합니다. 그렇지 않으면 리더가 개요 트리를 평면화합니다.

엔진은 단일 출력 패스 동안 페이지 분할을 결정합니다. 처리 비용은 콘텐츠 길이에 대해 선형으로 증가하며 O(n)입니다. 예산은 wall_ms: 2000, peak_mb: 96입니다. 다중 페이지 xref와 개요 조립 때문에 실제 실행 시간은 단일 페이지 레시피보다 약간 더 길게 나타납니다. 스트리밍 모델은 메모리를 제한된 상태로 유지하며, 개요는 작은 평면 목록입니다.

CSS 지원 매트릭스 발췌(Verified 행만)

섹션 제목: “CSS 지원 매트릭스 발췌(Verified 행만)”

여기서는 진실성 감사를 거친 CSS 지원 매트릭스에서 Verified 행만 재현합니다.

W3C 모듈레벨상태증거
CSS Fragmentation(css_break_3)3Verifiedsrc/Html/Fragmentation/, tests/Unit/Html/PagedMedia/
CSS Table(css_tables_3)3Verifiedsrc/Html/Table/ + 골든 PDF
CSS Cascading and Inheritance(css_cascade_3)3Verifiedsrc/Html/Cascade/

@page 명명된 페이지 선택자는 CSS Paged Media의 일부입니다. 이에 의존하기 전에 매트릭스에서 해당 모듈의 현재 등급을 확인해야 합니다.

단일 패스 스트리밍 제약 조건(ADR-001)

섹션 제목: “단일 패스 스트리밍 제약 조건(ADR-001)”

엔진은 스트림이 흐르는 동안 페이지 나누기를 출력합니다. 다시 흐르게 할 수 있는 보존된 트리가 없으므로, 나누기 결정은 한 번 내려지면 최종적입니다. 일부 콘텐츠에는 레이아웃 이후 확정된 페이지 번호가 필요합니다. 예를 들어 상호 참조가 그렇습니다. 그러한 콘텐츠는 제약을 받으므로, 그 한계를 염두에 두고 작성해야 합니다.

페이지 분할은 파서가 아니라 페이지 나누기 컨트롤러가 책임집니다. 파서는 원시 페이지 전환 연산자를 출력하지 않으며, 컨트롤러 계약을 통해 나누기를 요청합니다.

대용량 문서를 위한 메모리 예산

섹션 제목: “대용량 문서를 위한 메모리 예산”

스트리밍 모델은 모든 페이지를 한 번에 보유하는 대신 현재 페이지 버퍼와 평면 개요 목록을 보유합니다. 엔진이 완료된 페이지를 플러시하기 때문에 매우 긴 문서도 ADR-020 상한 내에 유지됩니다. 표와 플렉스 컨테이너는 여전히 컨텍스트당 5,000개 노드 제한을 따릅니다.

악의적인 문서가 무제한 메모리를 강제할 수는 없습니다. 요소 및 중첩 상한(ADR-001)과 컨텍스트당 노드 예산(ADR-020)이 작업을 제한합니다. 사용자가 제공한 긴 콘텐츠의 길이와 구조를 검증해야 합니다. 엔진은 공격자가 제어하는 개요 제목을 결코 해석하지 않고 텍스트로 렌더링합니다.

설명사양조항reference_id(참조 ID)
각 개요 항목은 대상과 연결될 수 있으므로 사용자가 해당 항목으로 바로 이동합니다.ISO 32000-2iso32000_2_sec12#x1.x5.p4
개요 항목의 Dest 항목은 해당 항목이 활성화될 때 표시되는 대상을 지정합니다.ISO 32000-2iso32000_2_sec12#x1.x11.p30

이 레시피는 NextPDF가 긴 콘텐츠를 흐르게 하고 개요를 구성하는 방법을 보여 줍니다. CSS Fragmentation은 지원 매트릭스에서 Verified로 등급이 매겨져 있습니다.

해당 없음.