Pro 版本
Writer — 深入參考
Writer 模組會寫入 PDF 增量更新(incremental-update)修訂版,並將小物件封裝進 Object Stream。增量 writer 會強制執行一條 fail-closed 的唯附加(append-only)規則:緩衝區在某次修訂版之前所持有的每一個位元組,在該修訂版之後都必須維持不變。Object Stream 建構器會把符合資格的物件分組到單一個 FlateDecode 壓縮的 /Type /ObjStm 物件中,並受限於一個有界的大小上限。
可用性與授權
標題為「可用性與授權」的區段此能力隨 NextPDF Pro(nextpdf/pro)出貨,並以 Pro 層級授權信封啟用。缺少該授權資格的部署不會載入此能力的類別。比較版本並取得授權。沒有個別功能的授權旗標;程式碼隨 Pro 版本一併出貨。
公開 API 介面
標題為「公開 API 介面」的區段本模組位於 NextPDF\Pro\Writer 命名空間之下。所有公開符號列於下方。Value object 為不可變的 final readonly 類別。
| 符號 | 參數 | 預設行為 | 回傳 | 拋出或失敗於 | 備註 |
|---|---|---|---|---|---|
IncrementalUpdateWriter::writeRevision | BinaryBuffer $buffer, ObjectRegistry $registry, int $prevXrefOffset, int $catalogObject, array $catalogEntries, array $catalogUpdates, array $newObjectNumbers, string $fileId | 靜態。以合併後的項目重寫 catalog,為新增與修改的物件附加一個傳統交叉參照表,並寫入帶有 /Size、/Root、/Prev 與 /ID 的 trailer。之後驗證修訂版前的前綴是否位元組相等。 | int — 新交叉參照表的位元組偏移 | 唯附加前綴檢查失敗時拋出 \NextPDF\Exception\WriterException;getWriterState() 回傳 dss-append-only-invariant | 靜態進入點。違規時無可用輸出。 |
ObjectStreamWriter::addObject | int $objectNumber, string $content | 經大小檢查後將一個物件附加至待處理串流。 | void | 合併後的索引加主體會超過 65,536 個位元組時拋出 OverflowException | $content 不含 N 0 obj / endobj 包裹。 |
ObjectStreamWriter::canAccept | string $content | 估算索引開銷並將累計總計與上限比對。 | bool | 不拋出 | 純述詞;不改變狀態。 |
ObjectStreamWriter::build | 無 | 建立索引、串接各主體、以 FlateDecode 壓縮,並包裹 /Type /ObjStm 字典。 | string — 原始 Object Stream 內容 | 未加入任何物件時,或 zlib 壓縮失敗時拋出 ObjectStreamWriteException | 呼叫端指派物件編號並包裹標記。 |
ObjectStreamWriter::getEntries | 無 | 為累積的物件重新計算相對於主體的偏移。 | list<ObjectStreamEntry> | 不拋出 | 偏移相對於主體區段。 |
ObjectStreamWriter::count | 無 | 回報已累積的物件數量。 | int | 不拋出 | — |
ObjStmCompressor::__construct | int $maxStreamSize = 65536, int $maxObjectsPerStream = 200 | 儲存用於分組的大小與物件數量上限。 | — | 不拋出 | 預設值符合本模組的 Object Stream 調校。 |
ObjStmCompressor::groupObjects | list<array{number: int, generation?: int, content: string}> $objects | 過濾掉不符資格的物件,再將其餘物件封裝進 writer,並受大小與數量上限約束。 | list<ObjectStreamWriter> | 不拋出;不符資格的物件會被略過 | generation 非零的物件會落入一般序列化。 |
ObjStmCompressor::isEligible | string $content, int $generation = 0 | 拒絕串流物件、/Encrypt、/XRef、/Catalog,以及任何 generation 非零者。 | bool | 不拋出 | /Type 比對容忍空白與 #xx 轉義。 |
ObjStmCompressor::writeToBuffer | list<ObjectStreamWriter> $streams, BinaryBuffer $buffer, ObjectRegistry $registry | 為每個串流配置一個載體物件、登記 type-2 壓縮項目,並寫入每個 ObjStm 區塊。 | list<int> — 載體物件編號 | 罕見壓縮失敗時,傳遞來自 build() 的 ObjectStreamWriteException | 在寫入不符資格的物件之後、發射交叉參照之前執行。 |
ObjStmCompressor::estimateSavings | list<ObjectStreamWriter> $streams, int $originalSize | 建立每個串流以量測壓縮後大小與原始大小的對比。 | ObjStmCompressionResult | 罕見壓縮失敗時,傳遞來自 build() 的 ObjectStreamWriteException | 唯讀量測輔助方法。 |
ObjectStreamEntry::__construct | int $objectNumber, string $content, int $offset | 一個已封裝物件與其主體偏移的不可變記錄。 | — | 不拋出 | final readonly;公開屬性。 |
ObjStmCompressionResult::__construct | int $originalObjectCount, int $streamCount, int $estimatedOriginalSize, int $estimatedCompressedSize | 不可變的度量容器。 | — | 不拋出 | final readonly;公開屬性。 |
ObjStmCompressionResult::savedBytes | 無 | 回傳原始大小減去壓縮後大小。 | int | 不拋出 | 當封裝反而膨脹資料時可能為負。 |
ObjStmCompressionResult::savedPercent | 無 | 回傳縮減的百分比。 | float | 不拋出 | 當原始大小為零時回傳 0.0。 |
ObjStmCompressionResult::compressionRatio | 無 | 回傳壓縮後大小相對於原始大小的比值。 | float | 不拋出 | 當原始大小為零時回傳 1.0。 |
ObjectStreamWriteException | — | 表示一次 Object Stream 建立失敗。 | — | 繼承 RuntimeException | 由 build() 拋出;為向後相容可透過 RuntimeException 攔截。 |
進入點簽章
標題為「進入點簽章」的區段final class IncrementalUpdateWriter{ public static function writeRevision( BinaryBuffer $buffer, ObjectRegistry $registry, int $prevXrefOffset, int $catalogObject, array $catalogEntries, array $catalogUpdates, array $newObjectNumbers, string $fileId, ): int;}final class ObjectStreamWriter{ public function addObject(int $objectNumber, string $content): void; public function canAccept(string $content): bool; public function build(): string; /** @return list<ObjectStreamEntry> */ public function getEntries(): array; public function count(): int;}final class ObjStmCompressor{ public function __construct( int $maxStreamSize = 65536, int $maxObjectsPerStream = 200, );
/** * @param list<array{number: int, generation?: int, content: string}> $objects * @return list<ObjectStreamWriter> */ public function groupObjects(array $objects): array;
public function isEligible(string $content, int $generation = 0): bool;
/** * @param list<ObjectStreamWriter> $streams * @return list<int> */ public function writeToBuffer(array $streams, BinaryBuffer $buffer, ObjectRegistry $registry): array;
/** @param list<ObjectStreamWriter> $streams */ public function estimateSavings(array $streams, int $originalSize): ObjStmCompressionResult;}行為合約
標題為「行為合約」的區段writeRevision 會寫入一個增量更新修訂版。它會在寫入之前先對既有的緩衝區前綴拍下快照。它會以合併後的項目重寫 catalog、登記新的物件偏移、寫入一個分組為連續子段的傳統交叉參照表,並寫入一個帶有 /Size、/Root、/Prev 與 /ID 的 trailer。寫入後,它會再次比對前綴。若任何較早的位元組改變了,它會引發帶有唯附加違規狀態的 WriterException,且不會回傳可用的輸出。在成功時,它會回傳新交叉參照表的位元組偏移,以供串接後續修訂版。跨修訂版混用交叉參照表與串流是被允許的。
ObjectStreamWriter 會累積物件。當合併後的索引與主體會超過上限(未壓縮 65,536 個位元組)時,addObject 會引發一個溢位錯誤。build 會在串流為空時引發錯誤;否則它會壓縮索引加主體,並回傳帶有 /Type /ObjStm、/N、/First、/Length 與 /Filter /FlateDecode 項目的 Object Stream 內容。由呼叫端指派物件編號並包裹 N 0 obj / endobj 標記。
ObjStmCompressor 會決定要封裝哪些物件。它會排除串流物件、加密字典、交叉參照串流、文件 catalog,以及任何 generation 編號非零的物件。writeToBuffer 會為每個串流配置一個載體物件、將每個已封裝物件登記為 type-2 壓縮交叉參照項目,並在目前的緩衝區偏移處寫入 ObjStm 區塊。estimateSavings 會建立每個串流以計算大小度量,且不會變動緩衝區。
邊界案例與失敗模式
標題為「邊界案例與失敗模式」的區段- 唯附加檢查會複製既有前綴。其成本會隨已寫入文件的大小增長。此成本是刻意的,用以保護已簽署的位元組。
- Object Stream 上限適用於未壓縮的索引加主體。請將加密字典與其他被排除的物件型別,以直接間接物件(direct indirect objects)放置。
/Type排除容忍任意的 token 間空白與#xx十六進位轉義。諸如/Type /Encrypt、/Type\n/Encrypt與/Type /#45ncrypt等形式都會被拒絕,而不僅限於標準字面拼法。- 任何帶有 generation 編號非零的物件都會被視為不符資格,並落入一般的
N G obj … endobj序列化,因為壓縮物件的 generation 隱含為零。 writeToBuffer必須在所有不符資格的物件都寫入之後、且在發射交叉參照之前執行。已封裝的物件不得再另行單獨序列化。
FIPS 模式行為
標題為「FIPS 模式行為」的區段Writer 模組不進行任何密碼學運算。它透過在某個較早位元組會改變時拒絕發射,來保護已簽署的位元組——這是一項位元組相等性測試,而非密碼學測試。用於簽署與雜湊的 FIPS 演算法選擇由簽署模組管轄,而非由本 writer 管轄。啟用或停用 FIPS 模式不會改變任何 Writer 方法的行為。
一致性
標題為「一致性」的區段NextPDF 依 ISO 32000-2:2020 實作本模組。增量 writer 遵循 §7.5.6 增量更新文法:每個修訂版會附加一個僅涵蓋新增、變更或刪除物件的交叉參照區段,以及一個其 /Prev 項目給出前一個交叉參照偏移的 trailer。Object Stream 建構器遵循 §7.5.7 object-stream 模型:一個由物件編號與偏移對組成的索引(偏移自 /First 項目起算、以遞增順序排列)置於已封裝的物件主體之前。兩處條款參考皆已對照 ISO 32000-2:2020 語料庫驗證。用於 PAdES B-LT 與 B-LTA 工作流程的修訂版串接遵循 ETSI EN 319 142-1 §5.4,如原始碼中所註記。對某條款的支援是一項工程能力聲明,而非認證;NextPDF 未持有任何正式的一致性認證。
開發備註
標題為「開發備註」的區段- 以
composer require nextpdf/pro:^3安裝套件。這些類別解析於NextPDF\Pro\Writer之下。 IncrementalUpdateWriter::writeRevision是一個靜態進入點;它在修訂版之間不持有任何實例狀態。ObjectStreamEntry、ObjStmCompressionResult、IncrementalUpdateWriter與該壓縮器共同構成本模組的公開介面;此儲存庫並未為其出貨任何可執行範例。- 來自
writeRevision的WriterException表示一次唯附加違規。請將其視為硬性失敗並丟棄緩衝區。 - Object Stream 載體是間接物件;由呼叫端透過 registry 指派其物件編號。
發布邊界
標題為「發布邊界」的區段本頁僅記錄外部可觀察的行為與所支援的公開 API 介面。內部命名空間路徑、輔助類別、機制表、runbook 檔名與工單前綴皆不在範圍內。