Phân trang nội dung HTML dài qua nhiều trang
Tổng quan nhanh
Phần tiêu đề “Tổng quan nhanh”Dùng ngắt trang tự động để dàn nội dung dài qua nhiều trang. Thêm mục lục để người đọc chuyển nhanh giữa các phần. Công thức này dựa trên examples/12-bookmarks-and-toc.php.
Cài đặt
Phần tiêu đề “Cài đặt”composer require nextpdf/core:^3Dùng ràng buộc phiên bản này cho gói nextpdf/core. Ví dụ chạy trên PHP 8.4.
Tổng quan khái niệm
Phần tiêu đề “Tổng quan khái niệm”setAutoPageBreak(true, $margin) cho engine biết cần bắt đầu một trang mới trước khi nội dung vượt qua ngưỡng lề dưới. Engine tách các đoạn văn bản dài được ghi bằng multiCell() hoặc writeHtml() tại ranh giới đó. Mô-đun Cascading Style Sheets (CSS) Fragmentation (css_break_3) được xếp hạng Verified trong ma trận hỗ trợ và hỗ trợ hành vi ngắt trong pipeline Hypertext Markup Language (HTML).
bookmark($title, $level) thêm một mục lục tại vị trí hiện tại. Một mục lục Portable Document Format (PDF) được gắn với một điểm đến để người đọc nhảy trực tiếp đến một trang (ISO 32000-2). Engine ghi điểm đến đó dưới dạng mục Dest của mục lục (ISO 32000-2). Dùng tham số level để lồng các mục thành một mục lục phân cấp trong thanh bên của trình đọc.
Pipeline vẫn chạy theo chế độ một lượt (ADR-001). Engine quyết định phân trang ngay trong lúc phát luồng, mà không giữ lại cây bố cục.
Bề mặt API
Phần tiêu đề “Bề mặt API”setAutoPageBreak(bool $enabled, float $margin = 20): static—NextPDF\Core\Concerns\HasPages.bookmark(string $title, int $level = 0, float $y = -1): static—NextPDF\Core\Concerns\HasNavigation.multiCell(...)/writeHtml(string $html): static—NextPDF\Core\Concerns\HasTextOutput.
Bảng PHPDoc đầy đủ được sinh từ mã nguồn.
Mã ví dụ — bắt đầu nhanh
Phần tiêu đề “Mã ví dụ — bắt đầu nhanh”<?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');Mã ví dụ — triển khai thực tế
Phần tiêu đề “Mã ví dụ — triển khai thực tế”Ví dụ khép kín này chạy trong harness. Ví dụ dựng một tài liệu nhiều chương với mục lục lồng nhau và ngắt trang tự động, đồng thời bám sát 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";Đầu ra chuẩn (STDOUT) kỳ vọng:
Wrote paginate-long-html.pdfTrường hợp đặc biệt & điểm cần lưu ý
Phần tiêu đề “Trường hợp đặc biệt & điểm cần lưu ý”- Tắt rồi để quên. Khi ngắt trang tự động bị tắt, engine cắt phần nội dung vượt quá lề dưới thay vì dàn sang trang khác. Hãy bật lại trước khi có nội dung dài.
- Nội dung không thể tách. Một khối đơn lẻ cao hơn chiều cao trang khả dụng có thể gây ra
UnsplittableContentException. Một hàng bảng rất cao hoặc một ảnh lớn có thể gây ra điều này. Hãy tách nhỏ nội dung nguồn. - Đặt bookmark trước nội dung. Gọi
bookmark()tại vị trí bạn muốn điểm đến trỏ tới. Hãy đặt nó ngay trước tiêu đề kế tiếp, trên trang mà bạn muốn. - Đầu trang và chân trang chiếm chỗ. Đầu trang hoặc chân trang được in làm giảm chiều cao nội dung khả dụng, và ngưỡng ngắt có tính đến điều đó. Tắt cả hai như trong ví dụ này sẽ cho bạn toàn bộ chiều cao phần thân.
- Lồng mục lục.
levellà độ sâu lồng. Một mục con ởlevel: 1phải đi sau một mục chalevel: 0. Nếu không, trình đọc sẽ làm phẳng cây mục lục.
Hiệu năng
Phần tiêu đề “Hiệu năng”Engine quyết định phân trang trong một lượt phát duy nhất. Chi phí tuyến tính theo độ dài nội dung, O(n). Ngân sách là wall_ms: 2000, peak_mb: 96. Thời gian thực tế cao hơn một chút so với các công thức một trang, vì tham chiếu chéo (xref) đa trang và việc dựng mục lục cần thêm xử lý. Mô hình luồng giữ bộ nhớ trong giới hạn; mục lục vẫn chỉ là một danh sách phẳng nhỏ.
Trích đoạn ma trận hỗ trợ CSS (chỉ các hàng Verified)
Phần tiêu đề “Trích đoạn ma trận hỗ trợ CSS (chỉ các hàng Verified)”Bảng này chỉ liệt kê lại các hàng Verified đã được kiểm chứng từ ma trận hỗ trợ CSS.
| Mô-đun W3C | Cấp độ | Trạng thái | Bằng chứng |
|---|---|---|---|
CSS Fragmentation (css_break_3) | 3 | Verified | src/Html/Fragmentation/, tests/Unit/Html/PagedMedia/ |
CSS Table (css_tables_3) | 3 | Verified | src/Html/Table/ + các PDF chuẩn (golden) |
CSS Cascading and Inheritance (css_cascade_3) | 3 | Verified | src/Html/Cascade/ |
@page là các selector trang được đặt tên, thuộc về CSS Paged Media. Trước khi dựa vào chúng, hãy tra ma trận để biết hạng hiện tại của mô-đun đó.
Ràng buộc của luồng một lượt (ADR-001)
Phần tiêu đề “Ràng buộc của luồng một lượt (ADR-001)”Engine phát ra các ngắt trang khi luồng được xử lý. Vì không giữ lại cây nào để dàn lại, mỗi quyết định ngắt là quyết định cuối cùng. Một số nội dung, chẳng hạn như tham chiếu chéo, cần biết số trang cuối cùng sau khi dàn trang. Nội dung đó bị ràng buộc bởi giới hạn này, vì vậy hãy tính đến giới hạn đó khi viết.
Hợp đồng giữa các lớp (ADR-010)
Phần tiêu đề “Hợp đồng giữa các lớp (ADR-010)”Phân trang thuộc về bộ điều khiển ngắt trang, không phải bộ phân tích cú pháp. Bộ phân tích cú pháp không phát ra các toán tử chuyển trang thô; nó yêu cầu ngắt trang thông qua hợp đồng của bộ điều khiển.
Ngân sách bộ nhớ cho tài liệu lớn
Phần tiêu đề “Ngân sách bộ nhớ cho tài liệu lớn”Mô hình luồng giữ bộ đệm trang hiện tại và danh sách mục lục phẳng, chứ không giữ tất cả các trang cùng lúc. Một tài liệu rất dài vẫn nằm trong trần giới hạn ADR-020 vì engine xả các trang đã hoàn tất. Bảng và flex container vẫn tuân theo giới hạn 5,000 nút mỗi ngữ cảnh.
Ghi chú bảo mật
Phần tiêu đề “Ghi chú bảo mật”Một tài liệu thù địch không thể buộc mức dùng bộ nhớ tăng không giới hạn. Các giới hạn về số phần tử và độ lồng (ADR-001), cùng với ngân sách nút theo từng ngữ cảnh (ADR-020), sẽ khống chế khối lượng xử lý. Hãy kiểm tra độ dài và cấu trúc của nội dung dài do người dùng cung cấp. Engine kết xuất tiêu đề mục lục do kẻ tấn công kiểm soát dưới dạng văn bản và không bao giờ diễn giải nội dung đó.
Tuân thủ
Phần tiêu đề “Tuân thủ”| Phát biểu | Đặc tả | Điều khoản | reference_id |
|---|---|---|---|
| Mỗi mục lục có thể được gắn với một điểm đến để người dùng nhảy trực tiếp đến nó. | ISO 32000-2 | iso32000_2_sec12#x1.x5.p4 | |
| Mục Dest của một mục lục đặt tên điểm đến được hiển thị khi mục đó được kích hoạt. | ISO 32000-2 | iso32000_2_sec12#x1.x11.p30 |
Công thức này cho thấy cách NextPDF dàn nội dung dài và dựng mục lục. Ma trận hỗ trợ xếp hạng CSS Fragmentation là Verified.
Bối cảnh thương mại
Phần tiêu đề “Bối cảnh thương mại”Không áp dụng.