Перейти к содержимому
getnextpdf.com

Pro редакция

Writer — глубокий справочник

Модуль Writer записывает ревизии инкрементального обновления PDF и упаковывает мелкие объекты в Object Stream. Инкрементальный writer применяет отказоустойчивое правило «только дописывание»: каждый байт, содержавшийся в буфере до ревизии, должен остаться неизменным после неё. Построитель Object Stream группирует подходящие объекты в один сжатый FlateDecode объект /Type /ObjStm в пределах ограниченного размера.

Эта возможность поставляется в NextPDF Pro (nextpdf/pro) и активируется лицензионным конвертом уровня Pro. Развёртывание без этого права не загружает классы возможности. Сравните редакции и получите лицензию. Отдельного флага лицензии на функцию нет; код поставляется вместе с редакцией Pro.

Модуль находится в пространстве имён NextPDF\Pro\Writer. Все публичные символы перечислены ниже. Объекты-значения — неизменяемые классы final readonly.

СимволПараметрыПоведение по умолчаниюВозвращаетВозбуждает или завершается ошибкойПримечания
IncrementalUpdateWriter::writeRevisionBinaryBuffer $buffer, ObjectRegistry $registry, int $prevXrefOffset, int $catalogObject, array $catalogEntries, array $catalogUpdates, array $newObjectNumbers, string $fileIdСтатический. Перезаписывает каталог с объединёнными записями, дописывает традиционную таблицу перекрёстных ссылок для новых и изменённых объектов и пишет трейлер с /Size, /Root, /Prev и /ID. После этого проверяет, что префикс до ревизии байт-в-байт совпадает.int — байтовое смещение новой таблицы перекрёстных ссылок\NextPDF\Exception\WriterException, когда проверка «только дописывание» не проходит; getWriterState() возвращает dss-append-only-invariantСтатическая точка входа. При нарушении пригодного вывода нет.
ObjectStreamWriter::addObjectint $objectNumber, string $contentДописывает один объект в ожидающий поток после проверки размера.voidOverflowException, когда совокупный индекс плюс тело превысили бы 65 536 байт$content не включает обёртки N 0 obj / endobj.
ObjectStreamWriter::canAcceptstring $contentОценивает накладные расходы индекса и проверяет текущую сумму относительно максимума.boolНе возбуждаетЧистый предикат; без изменения состояния.
ObjectStreamWriter::buildнетСтроит индекс, конкатенирует тела, сжимает FlateDecode и оборачивает словарь /Type /ObjStm.string — сырое содержимое Object StreamObjectStreamWriteException, когда не было добавлено ни одного объекта или при сбое сжатия zlibВызывающая сторона назначает номер объекта и оборачивает маркеры.
ObjectStreamWriter::getEntriesнетПересчитывает смещения накопленных объектов относительно тела.list<ObjectStreamEntry>Не возбуждаетСмещения отсчитываются от секции тела.
ObjectStreamWriter::countнетСообщает число накопленных объектов.intНе возбуждает
ObjStmCompressor::__constructint $maxStreamSize = 65536, int $maxObjectsPerStream = 200Сохраняет пределы размера и количества объектов, используемые при группировке.Не возбуждаетЗначения по умолчанию соответствуют настройке Object Stream модуля.
ObjStmCompressor::groupObjectslist<array{number: int, generation?: int, content: string}> $objectsОтфильтровывает непригодные объекты, затем упаковывает остальные в writer’ы в пределах размера и количества.list<ObjectStreamWriter>Не возбуждает; непригодные объекты пропускаютсяОбъекты с ненулевым поколением проходят к обычной сериализации.
ObjStmCompressor::isEligiblestring $content, int $generation = 0Отклоняет объекты-потоки, /Encrypt, /XRef, /Catalog и любое ненулевое поколение.boolНе возбуждаетСопоставление /Type терпимо к пробелам и #xx-экранированию.
ObjStmCompressor::writeToBufferlist<ObjectStreamWriter> $streams, BinaryBuffer $buffer, ObjectRegistry $registryВыделяет объект-носитель на каждый поток, регистрирует сжатые записи типа 2 и пишет каждый блок ObjStm.list<int> — номера объектов-носителейПробрасывает ObjectStreamWriteException из build() при редком сбое сжатияВыполняется после записи непригодных объектов и до эмиссии перекрёстных ссылок.
ObjStmCompressor::estimateSavingslist<ObjectStreamWriter> $streams, int $originalSizeСтроит каждый поток, чтобы измерить сжатый размер относительно исходного.ObjStmCompressionResultПробрасывает ObjectStreamWriteException из build() при редком сбое сжатияВспомогательный инструмент измерения только для чтения.
ObjectStreamEntry::__constructint $objectNumber, string $content, int $offsetНеизменяемая запись одного упакованного объекта и его смещения в теле.Не возбуждаетfinal readonly; публичные свойства.
ObjStmCompressionResult::__constructint $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 пишет одну ревизию инкрементального обновления. Перед записью он делает снимок существующего префикса буфера. Он перезаписывает каталог с объединёнными записями, регистрирует смещения новых объектов, пишет традиционную таблицу перекрёстных ссылок, сгруппированную в смежные подсекции, и пишет трейлер с /Size, /Root, /Prev и /ID. После записи он снова сравнивает префикс. Если хоть один более ранний байт изменился, он возбуждает WriterException, несущее состояние нарушения правила «только дописывание», и не возвращает пригодного вывода. При успехе он возвращает байтовое смещение новой таблицы перекрёстных ссылок для сцепления дальнейших ревизий. Смешивание таблиц и потоков перекрёстных ссылок между ревизиями разрешено.

ObjectStreamWriter накапливает объекты. addObject возбуждает ошибку переполнения, когда совокупный индекс и тело превысили бы максимум в 65 536 байт без сжатия. build возбуждает ошибку на пустом потоке; в противном случае он сжимает индекс плюс тело и возвращает содержимое Object Stream с записями /Type /ObjStm, /N, /First, /Length и /Filter /FlateDecode. Вызывающая сторона назначает номер объекта и оборачивает маркеры N 0 obj / endobj.

ObjStmCompressor решает, какие объекты упаковывать. Он исключает объекты-потоки, словари шифрования, потоки перекрёстных ссылок, каталог документа и любой объект с ненулевым номером поколения. writeToBuffer выделяет объект-носитель на каждый поток, регистрирует каждый упакованный объект как сжатую запись перекрёстных ссылок типа 2 и пишет блок ObjStm по текущему смещению буфера. estimateSavings строит каждый поток, чтобы вычислить метрики размера, не изменяя буфер.

  • Проверка «только дописывание» копирует существующий префикс. Её стоимость растёт с размером уже записанного документа. Эта стоимость преднамеренна и защищает подписанные байты.
  • Предел Object Stream применяется к индексу плюс телу без сжатия. Размещайте словарь шифрования и другие исключённые типы объектов как прямые косвенные объекты.
  • Исключение по /Type терпимо к произвольным пробелам между токенами и #xx-шестнадцатеричному экранированию. Формы вроде /Type /Encrypt, /Type\n/Encrypt и /Type /#45ncrypt отклоняются все, а не только каноническое буквальное написание.
  • Любой объект с ненулевым номером поколения считается непригодным и проходит к обычной сериализации N G obj … endobj, поскольку поколение сжатого объекта неявно равно нулю.
  • writeToBuffer должен выполняться после записи всех непригодных объектов и до эмиссии перекрёстных ссылок. Упакованные объекты не должны также сериализоваться отдельно.

Модуль Writer не выполняет криптографических операций. Он защищает подписанные байты, отказываясь эмитировать вывод, когда более ранний байт изменился бы, что является проверкой байтового равенства, а не криптографической. Выбор алгоритмов FIPS для подписания и хеширования определяется модулем подписания, а не этим writer. Включение или отключение режима FIPS не меняет поведения ни одного метода Writer.

NextPDF реализует модуль в соответствии с ISO 32000-2:2020. Инкрементальный writer следует грамматике инкрементального обновления §7.5.6: каждая ревизия дописывает секцию перекрёстных ссылок, охватывающую только новые, изменённые или удалённые объекты, и трейлер, чья запись /Prev даёт смещение предыдущих перекрёстных ссылок. Построитель Object Stream следует модели объектных потоков §7.5.7: индекс пар «номер объекта — смещение», где смещения отсчитываются от записи /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 и компрессор вместе образуют публичную поверхность модуля; репозиторий не поставляет для него запускаемого примера.
  • WriterException из writeRevision указывает на нарушение правила «только дописывание». Считайте это жёстким сбоем и отбросьте буфер.
  • Носители Object Stream — косвенные объекты; вызывающая сторона назначает их номера через реестр.

Эта страница документирует только внешне наблюдаемое поведение и поддерживаемую поверхность публичного API. Внутренние пути пространств имён, вспомогательные классы, таблицы механизмов, имена файлов runbook и префиксы тикетов вне области рассмотрения.