Bỏ qua để đến nội dung

ContentStream: bộ phát luồng nội dung PDF

Module ContentStream phát các toán tử nội dung được đánh dấu của Portable Document Format (PDF). Module này mở và đóng thẻ cấu trúc cùng artifact, theo dõi độ sâu lồng nhau và trả về vùng đệm toán tử.

Terminal window
composer require nextpdf/core:^3

ContentStreamBuilder là lớp duy nhất của module này. Lớp này xây dựng lớp nội dung được đánh dấu của một luồng nội dung trang. Một luồng nội dung mã hóa nội dung trang thành chuỗi toán tử — ISO 32000-2 §8. Sau đó, builder phát các toán tử nội dung được đánh dấu bao quanh nội dung đó.

append() thêm nguyên văn các byte toán tử thô. Builder không escape dữ liệu đầu vào này. Bạn chịu trách nhiệm về tính hợp lệ của dữ liệu đó. Hãy dùng ranh giới này khi HTML pipeline và module Graphics cần chèn xen kẽ các toán tử riêng của chúng.

beginTag() mở một chuỗi được gắn thẻ cấu trúc. Phương thức này phát một toán tử BDC kèm danh sách thuộc tính MCID, theo ISO 32000-2 §14.6. endTag() phát toán tử EMC tương ứng. Builder đếm độ sâu lồng nhau. Nếu bạn gọi endTag() khi không có chuỗi nào đang mở, nó sẽ ném PageLayoutException thay vì ghi một EMC không cân bằng.

beginArtifact() mở một chuỗi artifact. Hãy dùng artifact cho phần trang trí phân trang — đầu trang, chân trang, số trang và đường kẻ — vốn phải nằm ngoài cây cấu trúc, theo ISO 32000-2 §14.8.2.2. Subtype là một trong bốn giá trị ISO: Pagination, Layout, Page, hoặc Background. Hãy ưu tiên dùng enum ArtifactSubtype có kiểu. Phiên bản nạp chồng nhận chuỗi được kiểm tra hợp lệ theo enum, nên giá trị không chuẩn sẽ thất bại ngay lập tức.

relabelTag() ghi đè tại chỗ một thẻ đã được phát trước đó. finish() trả về toàn bộ vùng đệm và ném ngoại lệ nếu nội dung được đánh dấu không cân bằng. drain() trả về vùng đệm hiện có mà không kiểm tra cân bằng, dùng khi truyền theo từng phần. peek() trả về vùng đệm mà không tiêu thụ. reset() xóa trạng thái.

Phương thứcChữ kýVai trò
append()append(string $raw): voidThêm các byte toán tử thô nguyên văn (không escape)
beginTag()beginTag(string $structType, int $mcid): voidMở một chuỗi BDC cấu trúc
endTag()endTag(): voidĐóng chuỗi trong cùng bằng EMC
beginArtifact()beginArtifact(ArtifactSubtype|string $type): voidMở một chuỗi artifact
endArtifact()endArtifact(): voidĐóng artifact trong cùng
getMarkedContentDepth()getMarkedContentDepth(): intTrả về độ sâu lồng nhau hiện tại
relabelTag()relabelTag(string $old, string $new, int $mcid): voidGhi đè tại chỗ một thẻ đã phát
finish()finish(): stringTrả về toàn bộ vùng đệm; ném ngoại lệ nếu không cân bằng
drain()drain(): stringTrả về vùng đệm mà không kiểm tra cân bằng
peek()peek(): stringTrả về vùng đệm mà không tiêu thụ nó
reset()reset(): voidXóa toàn bộ trạng thái

Chạy composer docs:generate-api-php -- --module=ContentStream để tạo bảng PHPDoc đầy đủ.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\ContentStream\ContentStreamBuilder;
$builder = new ContentStreamBuilder();
$builder->beginTag('P', mcid: 0);
$builder->append("BT /F1 12 Tf 72 720 Td (Hello) Tj ET\n");
$builder->endTag();
$pageContent = $builder->finish();

Hãy dùng mẫu này để bọc một đoạn văn trong một thẻ cấu trúc và bọc chân trang trong một artifact. Mẫu này truyền vùng đệm theo từng phần bằng drain().

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Accessibility\ArtifactSubtype;
use NextPDF\ContentStream\ContentStreamBuilder;
$builder = new ContentStreamBuilder();
$builder->beginTag('H1', mcid: 0);
$builder->append($titleOperators);
$builder->endTag();
$builder->beginArtifact(ArtifactSubtype::Pagination);
$builder->append($footerOperators);
$builder->endArtifact();
if ($builder->getMarkedContentDepth() !== 0) {
throw new RuntimeException('Unbalanced marked content before flush.');
}
$chunk = $builder->drain();

Trường hợp đặc biệt và điểm cần lưu ý

Phần tiêu đề “Trường hợp đặc biệt và điểm cần lưu ý”
  • append() không escape dữ liệu đầu vào. Chỉ truyền các byte toán tử hợp lệ. Builder tin tưởng mã gọi.
  • endTag()endArtifact() ném ngoại lệ khi bị tràn dưới. Đừng bao giờ đóng một chuỗi chưa được mở.
  • finish() kiểm tra cân bằng và ném ngoại lệ khi độ sâu khác không. drain() thì không kiểm tra. Chỉ dùng drain() khi truyền theo từng phần.
  • Bộ đếm độ sâu không phân biệt thẻ với artifact. EMC đóng chuỗi trong cùng thuộc một trong hai loại. Hãy lồng các chuỗi theo đúng thứ tự.
  • Phiên bản nạp chồng nhận chuỗi của beginArtifact() được kiểm tra hợp lệ theo enum. Một subtype không chuẩn sẽ thất bại ngay tại lời gọi, chứ không phải trong kết quả đầu ra.
  • relabelTag() ghi đè một thẻ đã phát. Hãy dùng đúng mcid mà bạn đã dùng khi phát nó.

Mỗi thao tác là một phép nối chuỗi O(1), ngoại trừ relabelTag(), vốn thực hiện một phép ghi đè O(buffer). Module giữ một vùng đệm chuỗi và một bộ đếm độ sâu kiểu số nguyên. Module không phân tích cú pháp và chỉ cấp phát vùng đệm. Ngân sách tải tham chiếu là 1500 ms thời gian thực và 64 MB đỉnh. Module này vẫn thấp hơn mức đó rất xa.

append() là ranh giới tin cậy. Builder ghi byte nguyên văn, nên mã ở phía trên phải escape mọi chuỗi đi vào một toán tử literal-string. Bộ escape chuẩn là PdfStringEscaper::escapeLiteral() (ADR-015). Đừng bao giờ truyền văn bản người dùng chưa được escape qua append(). Các kiểm tra cân bằng trong endTag(), endArtifact(), và finish() ngăn một cây nội dung được đánh dấu sai định dạng đi đến Writer. Xem /modules/core/security/ để biết mô hình mối đe dọa của tài liệu.

Module phát các cấu trúc toán tử nội dung được đánh dấu nhất quán với ISO 32000-2: các cặp BDC/EMC kèm danh sách thuộc tính MCID theo §14.6, và các chuỗi artifact theo §14.8.2.2. Đây là các sự kiện về cách triển khai. Bằng chứng là src/ContentStream/ContentStreamBuilder.php, enum src/Accessibility/ArtifactSubtype.php, và tests/Unit/ContentStream/ContentStreamBuilderMarkedContentBalanceCoverageTest cùng với ContentStreamBuilderRelabelTagInvariantTest. Chúng không phải là tuyên bố về sự tuân thủ PDF/UA-2 hoặc PDF 2.0 đầu cuối. Một oracle bên ngoài kiểm tra hợp lệ cấu trúc tagged-PDF mà các toán tử này tham gia vào: tests/Integration/Accessibility/VeraPdfUa2GoldenTest đối chiếu một fixture được tạo ra với veraPDF cho hồ sơ PDF/UA-2. Test oracle đó bỏ qua khi không có tệp nhị phân veraPDF, nên đây là một cổng tùy chọn. Hãy phát biểu rằng module này “tạo ra các cấu trúc nội dung được đánh dấu; sự tuân thủ PDF/UA-2 được kiểm tra hợp lệ bởi veraPDF” thay vì khẳng định sự tuân thủ một cách không kèm điều kiện.