Pro редакция
Writer — глубокий справочник
Модуль Writer записывает ревизии инкрементального обновления PDF и упаковывает мелкие объекты в Object Stream. Инкрементальный writer применяет отказоустойчивое правило «только дописывание»: каждый байт, содержавшийся в буфере до ревизии, должен остаться неизменным после неё. Построитель Object Stream группирует подходящие объекты в один сжатый FlateDecode объект /Type /ObjStm в пределах ограниченного размера.
Доступность и лицензирование
Заголовок раздела «Доступность и лицензирование»Эта возможность поставляется в NextPDF Pro (nextpdf/pro) и активируется лицензионным конвертом уровня Pro. Развёртывание без этого права не загружает классы возможности. Сравните редакции и получите лицензию. Отдельного флага лицензии на функцию нет; код поставляется вместе с редакцией Pro.
Поверхность публичного API
Заголовок раздела «Поверхность публичного API»Модуль находится в пространстве имён NextPDF\Pro\Writer. Все публичные символы перечислены ниже. Объекты-значения — неизменяемые классы final readonly.
| Символ | Параметры | Поведение по умолчанию | Возвращает | Возбуждает или завершается ошибкой | Примечания |
|---|---|---|---|---|---|
IncrementalUpdateWriter::writeRevision | BinaryBuffer $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::addObject | int $objectNumber, string $content | Дописывает один объект в ожидающий поток после проверки размера. | void | OverflowException, когда совокупный индекс плюс тело превысили бы 65 536 байт | $content не включает обёртки N 0 obj / endobj. |
ObjectStreamWriter::canAccept | string $content | Оценивает накладные расходы индекса и проверяет текущую сумму относительно максимума. | bool | Не возбуждает | Чистый предикат; без изменения состояния. |
ObjectStreamWriter::build | нет | Строит индекс, конкатенирует тела, сжимает FlateDecode и оборачивает словарь /Type /ObjStm. | string — сырое содержимое Object Stream | ObjectStreamWriteException, когда не было добавлено ни одного объекта или при сбое сжатия zlib | Вызывающая сторона назначает номер объекта и оборачивает маркеры. |
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> | Не возбуждает; непригодные объекты пропускаются | Объекты с ненулевым поколением проходят к обычной сериализации. |
ObjStmCompressor::isEligible | string $content, int $generation = 0 | Отклоняет объекты-потоки, /Encrypt, /XRef, /Catalog и любое ненулевое поколение. | bool | Не возбуждает | Сопоставление /Type терпимо к пробелам и #xx-экранированию. |
ObjStmCompressor::writeToBuffer | list<ObjectStreamWriter> $streams, BinaryBuffer $buffer, ObjectRegistry $registry | Выделяет объект-носитель на каждый поток, регистрирует сжатые записи типа 2 и пишет каждый блок ObjStm. | list<int> — номера объектов-носителей | Пробрасывает ObjectStreamWriteException из build() при редком сбое сжатия | Выполняется после записи непригодных объектов и до эмиссии перекрёстных ссылок. |
ObjStmCompressor::estimateSavings | list<ObjectStreamWriter> $streams, int $originalSize | Строит каждый поток, чтобы измерить сжатый размер относительно исходного. | ObjStmCompressionResult | Пробрасывает ObjectStreamWriteException из build() при редком сбое сжатия | Вспомогательный инструмент измерения только для чтения. |
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 пишет одну ревизию инкрементального обновления. Перед записью он делает снимок существующего префикса буфера. Он перезаписывает каталог с объединёнными записями, регистрирует смещения новых объектов, пишет традиционную таблицу перекрёстных ссылок, сгруппированную в смежные подсекции, и пишет трейлер с /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должен выполняться после записи всех непригодных объектов и до эмиссии перекрёстных ссылок. Упакованные объекты не должны также сериализоваться отдельно.
Поведение в режиме FIPS
Заголовок раздела «Поведение в режиме FIPS»Модуль 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 и префиксы тикетов вне области рассмотрения.