ContentStream: PDF コンテンツストリームエミッター
ContentStream モジュールは、マークコンテンツオペレーターを出力します。構造タグとアーティファクトを開閉し、ネストの深さを追跡して、オペレーターバッファーを返します。
インストール
「インストール」という見出しのセクションcomposer require nextpdf/core:^3概念の概要
「概念の概要」という見出しのセクションContentStreamBuilder は、このモジュールで唯一のクラスです。ページコンテンツストリームのマークコンテンツレイヤーを構築します。コンテンツストリームは、ページコンテンツをオペレーターのシーケンスとしてエンコードします(ISO 32000-2 §8)。ビルダーは、そのコンテンツを囲むマークコンテンツオペレーターを出力します。
append() は、生のオペレーターバイトをそのまま追加します。ビルダーはこの入力をエスケープしません。その妥当性は呼び出し側の責任です。ここが、HTML パイプラインと Graphics モジュールがそれぞれのオペレーターを差し込むポイントです。
beginTag() は、構造タグの付いたシーケンスを開きます。BDC オペレーターを、MCID プロパティリストとともに出力します(ISO 32000-2 §14.6)。endTag() は、対応する EMC オペレーターを出力します。ビルダーはネストの深さをカウントします。開いているシーケンスがない状態で endTag() を呼び出すと、PageLayoutException をスローし、不均衡な EMC は書き込みません。
beginArtifact() は、アーティファクトシーケンスを開きます。アーティファクトは、構造ツリーの外に置かれなければならないページネーション装飾(ヘッダー、フッター、ページ番号、罫線)を保持します(ISO 32000-2 §14.8.2.2)。サブタイプは、4 つの ISO 値(Pagination、Layout、Page、Background)のいずれかです。型付きの ArtifactSubtype 列挙型を使用することを推奨します。文字列のオーバーロードは列挙型に対して検証されるため、非標準の値はただちに失敗します。
relabelTag() は、すでに出力されたタグをその場で書き換えます。finish() は、バッファー全体を返し、マークコンテンツが不均衡な場合はスローします。drain() は、インクリメンタルストリーミング向けに、均衡チェックなしでこれまでのバッファーを返します。peek() は、バッファーを消費せずに返します。reset() は、状態をクリアします。
API サーフェス
「API サーフェス」という見出しのセクション| メソッド | シグネチャー | 役割 |
|---|---|---|
append() | append(string $raw): void | 生のオペレーターバイトの追加(エスケープなし) |
beginTag() | beginTag(string $structType, int $mcid): void | BDC 構造シーケンスの開始 |
endTag() | endTag(): void | 最も内側のシーケンスの EMC による終了 |
beginArtifact() | beginArtifact(ArtifactSubtype|string $type): void | アーティファクトシーケンスの開始 |
endArtifact() | endArtifact(): void | 最も内側のアーティファクトの終了 |
getMarkedContentDepth() | getMarkedContentDepth(): int | 現在のネストの深さの取得 |
relabelTag() | relabelTag(string $old, string $new, int $mcid): void | 出力済みタグのその場での書き換え |
finish() | finish(): string | バッファー全体の取得。不均衡な場合はスロー |
drain() | drain(): string | 均衡チェックなしのバッファー取得 |
peek() | peek(): string | バッファーを消費しない取得 |
reset() | reset(): void | すべての状態のクリア |
完全な PHPDoc テーブルを取得するには、composer docs:generate-api-php -- --module=ContentStream を実行してください。
コードサンプル — クイックスタート
「コードサンプル — クイックスタート」という見出しのセクション<?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();コードサンプル — 本番
「コードサンプル — 本番」という見出しのセクションこの例では、段落を構造タグで、フッターをアーティファクトで囲みます。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();エッジケースと注意点
「エッジケースと注意点」という見出しのセクションappend()は入力をエスケープしません。有効なオペレーターバイトのみを渡してください。ビルダーは呼び出し側を信頼します。endTag()とendArtifact()は、アンダーフロー時にスローします。開いていないシーケンスは決して閉じないでください。finish()は均衡をチェックし、深さがゼロでない場合はスローします。drain()はチェックしません。drain()はインクリメンタルストリーミングの場合にのみ使用してください。- 深さカウンターは、タグとアーティファクトを区別しません。
EMCは、どちらの種類でも最も内側のシーケンスを閉じます。厳密な順序でネストしてください。 - 文字列を渡す
beginArtifact()のオーバーロードは、列挙型に対して検証されます。非標準のサブタイプは、出力時ではなく呼び出し時に失敗します。 relabelTag()は、出力済みのタグを書き換えます。出力時に使用したものと同じmcidを使用してください。
パフォーマンス
「パフォーマンス」という見出しのセクションすべての操作は O(1) の文字列追加であり、relabelTag() の場合は O(buffer) の書き換えです。モジュールは、1 つの文字列バッファーと 1 つの整数の深さカウンターを保持します。パース処理は行わず、バッファー以外のアロケーションもありません。リファレンスワークロードの予算は、実時間 1500 ms、ピーク 64 MB です。このモジュールはその予算を大きく下回ります。
セキュリティに関する注意
「セキュリティに関する注意」という見出しのセクションappend() は信頼境界です。ビルダーはバイトをそのまま書き込むため、上流のコードは、リテラル文字列オペレーターに到達するすべての文字列をエスケープする必要があります。正規のエスケーパーは PdfStringEscaper::escapeLiteral()(ADR-015)です。エスケープしていないユーザーテキストを append() に決して渡さないでください。endTag()、endArtifact()、finish() での均衡チェックにより、不正な形式のマークコンテンツツリーが Writer に到達するのを防ぎます。ドキュメントの脅威モデルについては、/modules/core/security/ を参照してください。
このモジュールは、ISO 32000-2 と整合するマークコンテンツオペレーター構造を 出力します。具体的には、BDC/EMC のペア(§14.6 に従い MCID プロパティリストを伴う)と、§14.8.2.2 に従うアーティファクトシーケンスです。これらは実装上の事実です。その根拠は、src/ContentStream/ContentStreamBuilder.php、src/Accessibility/ArtifactSubtype.php 列挙型、および tests/Unit/ContentStream/ContentStreamBuilderMarkedContentBalanceCoverageTest と ContentStreamBuilderRelabelTagInvariantTest です。これらは、エンドツーエンドの PDF/UA-2 または PDF 2.0 準拠を主張するものではありません。これらのオペレーターが構成するタグ付き PDF 構造は、外部のオラクルによって検証されます。tests/Integration/Accessibility/VeraPdfUa2GoldenTest が、生成されたフィクスチャを PDF/UA-2 プロファイルについて veraPDF に対してチェックします。このオラクルテストは veraPDF バイナリが存在しない場合はスキップされる ため、オプトインのゲートです。無条件の準拠を主張するのではなく、このモジュールは「マークコンテンツ構造を生成し、PDF/UA-2 準拠は veraPDF によって検証される」と記述してください。