Skip to content
getnextpdf.com

Pro edition

Writer

The Writer module appends incremental-update revisions to a PDF and packs small objects into Object Streams. The incremental writer enforces an append-only rule: bytes that existed before the revision must not change.

This capability ships in NextPDF Pro (nextpdf/pro) and activates with a Pro-tier license envelope. A deployment without that entitlement does not load the capability’s classes. Compare editions and get a license. There is no separate per-feature license flag; the code ships with the Pro edition.

Terminal window
composer require nextpdf/pro:^3

The code lives under the NextPDF\Pro\Writer namespace.

Two capabilities are provided:

  • IncrementalUpdateWriter writes a new revision. It re-writes the catalog with merged entries, appends a traditional cross-reference table for the new and modified objects, and writes a trailer that links to the previous revision. It enforces a fail-closed append-only rule.
  • ObjectStreamWriter groups small objects into a single compressed Object Stream. This reduces cross-reference table size and improves compression. It rejects objects that would exceed the maximum stream size and rejects an empty stream.

The append-only rule protects existing signatures. Every byte the buffer held before the revision must appear unchanged at the same position after the revision. If any earlier byte changes, the writer raises an error and does not produce output.

The load-bearing choice is where the append-only gate lives. It sits at writer scope, not only in higher-level orchestrators, so every present and future caller inherits fail-closed coverage. The check is a pure prefix-equality test: the writer snapshots the buffer prefix before appending, then confirms every earlier byte is unchanged afterward. This protects any signature whose /ByteRange covered the prefix, since one altered byte would silently invalidate it. Traditional cross-reference tables and a /Prev pointer carry the new revision, because incremental updates must append rather than rewrite. The verification cost is linear in the existing prefix, and that cost is accepted deliberately: signed-byte integrity outranks a second copy.

Design background: Incremental updates and why they matter.

  • IncrementalUpdateWriter::writeRevision(...) returns the byte offset of the new cross-reference table, so you can chain further revisions.
  • The writer verifies the original prefix is byte-equal before and after writing. A divergence raises a writer exception that carries an append-only-violation state.
  • The new revision uses a traditional cross-reference table and a trailer with a /Prev pointer; mixing tables and streams across revisions is permitted.
  • ObjectStreamWriter::addObject() raises an overflow error when adding an object would exceed the maximum stream size (65,536 bytes uncompressed for index plus body).
  • ObjectStreamWriter::build() raises an error when no objects were added; otherwise it returns the compressed Object Stream content.

The following reflects the documented public API. The repository does not ship a runnable example for this module.

use NextPDF\Pro\Writer\ObjectStreamWriter;
$writer = new ObjectStreamWriter();
$writer->addObject(10, $serializedObjectBody);
$objStm = $writer->build();
use NextPDF\Pro\Writer\IncrementalUpdateWriter;
$newXrefOffset = IncrementalUpdateWriter::writeRevision(
$buffer,
$registry,
$prevXrefOffset,
$catalogObject,
$catalogEntries,
$catalogUpdates,
$newObjectNumbers,
$fileId,
);
// A WriterException here means the append-only rule was violated.
// Treat it as a hard failure; do not emit the output.
  • The append-only check copies the existing prefix. The cost grows with the size of the already-written document. This cost is intentional and protects signed bytes.
  • The Object Stream size limit is on the combined index and body before compression. Group objects accordingly.
  • Object Streams must not contain certain object types (for example, the encryption dictionary). Place those as direct indirect objects.

The append-only verification is linear in the size of the existing document prefix. Object Stream packing reduces cross-reference size and improves compression at the cost of one extra compression pass. There is no published throughput figure. Measure with representative documents.

The incremental writer is fail-closed. If a code path would change a byte that an earlier signature covered, the writer raises an error instead of producing a document. This protects signature integrity for revision-chained workflows. No document content is logged.

The source annotates the incremental-update grammar and Object Stream model in ISO 32000-2 and the revision-chaining requirements in the ETSI EN 319 142-1 PAdES profile.

Enterprise adds higher-tier signature lifecycle features (long-term validation and renewal) that build on incremental updates at a behavior level. The Writer module provides the revision primitive only; those higher-tier features are documented separately and are not required to write a revision.

Without Pro, use NextPDF Core’s base writer; incremental-update revisions with the append-only gate and Object Stream packing are Pro additions. See /modules/writer/.

This page documents externally observable behavior and the supported public API surface only. Internal namespace paths, helper classes, mechanism tables, runbook filenames, and ticket prefixes are out of scope.