Техническая статья

HotPDF: потоки объектов и инкрементальные обновления в Delphi

HotPDF — нативная VCL PDF-библиотека для приложений Delphi и C++Builder, которым нужны прямое создание и редактирование PDF, формы, аннотации, шифрование, цифровые подписи, Unicode-шрифты, вывод с учетом стандартов и preflight-отчеты без внешнего PDF-runtime.

Эта статья предназначена для инженеров, которые поддерживают PDF, уже содержащие подписи, ревизии, сжатые объекты или историю исправлений. Она рассматривает потоки объектов и инкрементальные обновления как промышленную инженерию документов, а не как одиночный вызов компонента.

Практический риск состоит в том, что повторная запись файла как будто он был создан заново может отбросить историю ревизий, повредить подписи или скрыть повреждённые данные cross-reference. Поэтому процессу нужны письменный контракт, наблюдаемая диагностика и реалистичные регрессионные файлы.

Архитектурные решения

Понимайте существующую цепочку ревизий. Должны ли существующие подписи или журналы аудита оставаться действительными / политика сохранения, распаковки или повторного сжатия object stream

  • должны ли существующие подписи или журналы аудита оставаться действительными
  • политика сохранения, распаковки или повторного сжатия object stream
  • repair handling when cross-reference data is inconsistent
  • metadata and catalog updates that should be appended instead of rewritten

Порядок реализации

Выбирайте полную пересборку или инкрементальное сохранение осознанно. Порядок ниже делает сценарий удобным для проверки командами Delphi и C++Builder.

  1. inspect the source for signatures, xref streams, object streams, and prior revisions
  2. select incremental update only when the business goal requires preservation
  3. write changed objects to a new revision and leave untouched objects stable
  4. verify signatures, object counts, and cross-reference consistency after saving
  5. record the reason if a full rewrite was required for repair or normalization

Доказательства проверки

Фиксируйте доказательства ревизии. Храните эти поля вместе с результатом или записью поддержки.

  • source revision count, signature presence, xref style, and object stream count
  • save mode, changed object identifiers, and whether object streams were preserved
  • validator output before and after the update
  • signature status for every signed revision after the final file is written

Сжатые объекты усложняют диагностику поддержки

Потоки объектов, гибридные таблицы cross-reference и инкрементальные сохранения обычны для современных PDF. Процесс должен понимать, сохраняет ли он ревизию, добавляет новую ревизию или создаёт чистый выходной файл.

Вопросы для проверки перед выпуском

Перед выпуском в production команда должна уметь ответить на эти вопросы без чтения исходного кода

  • Who owns должны ли существующие подписи или журналы аудита оставаться действительными?
  • Какое доказательство подтверждает число ревизий исходника, наличие подписи, стиль xref и число object stream?
  • Что происходит, когда полная пересборка может сделать подписи недействительными даже при неизменном видимом содержимом?
  • Какой регрессионный файл фиксирует причину, если для исправления или нормализации потребовалась полная пересборка?

Замечания для инженерного ревью по потоки объектов и инкрементальные обновления

Используйте эти замечания, чтобы убедиться, что функция вышла за рамки демо и может быть обоснована на релизе, в поддержке и при эскалации клиента

  • Решение: должны ли существующие подписи или журналы аудита оставаться действительными. Точка приложения при реализации: select incremental update only when the business goal requires preservation. Доказательство приемки: validator output before and after the update. Триггер регрессии: object-stream compression can make diff-based support investigations misleading
  • Решение: политика сохранения, распаковки или повторного сжатия object stream. Точка приложения при реализации: write changed objects to a new revision and leave untouched objects stable. Доказательство приемки: signature status for every signed revision after the final file is written. Триггер регрессии: a full rewrite can invalidate signatures even when visible content is unchanged
  • Решение: repair handling when cross-reference data is inconsistent. Точка приложения при реализации: verify signatures, object counts, and cross-reference consistency after saving. Доказательство приемки: source revision count, signature presence, xref style, and object stream count. Триггер регрессии: repairing a damaged file may require a support note explaining lost revisions
  • Решение: metadata and catalog updates that should be appended instead of rewritten. Точка приложения при реализации: record the reason if a full rewrite was required for repair or normalization. Доказательство приемки: save mode, changed object identifiers, and whether object streams were preserved. Триггер регрессии: linearization can be lost after incremental updates unless the workflow rebuilds it
  • Решение: должны ли существующие подписи или журналы аудита оставаться действительными. Точка приложения при реализации: inspect the source for signatures, xref streams, object streams, and prior revisions. Доказательство приемки: validator output before and after the update. Триггер регрессии: object-stream compression can make diff-based support investigations misleading
  • Решение: политика сохранения, распаковки или повторного сжатия object stream. Точка приложения при реализации: select incremental update only when the business goal requires preservation. Доказательство приемки: signature status for every signed revision after the final file is written. Триггер регрессии: a full rewrite can invalidate signatures even when visible content is unchanged
  • Решение: repair handling when cross-reference data is inconsistent. Точка приложения при реализации: write changed objects to a new revision and leave untouched objects stable. Доказательство приемки: source revision count, signature presence, xref style, and object stream count. Триггер регрессии: repairing a damaged file may require a support note explaining lost revisions

Пограничные случаи

  • a full rewrite can invalidate signatures even when visible content is unchanged
  • repairing a damaged file may require a support note explaining lost revisions
  • linearization can be lost after incremental updates unless the workflow rebuilds it
  • object-stream compression can make diff-based support investigations misleading

Примечания по Delphi / C++Builder

HotPDF Component должен находиться за небольшим сервисным слоем, который принимает файлы, потоки, профили и учетные данные, а затем возвращает пути вывода, предупреждения, метрики и состояние проверки. Важные термины включают object stream, incremental update, xref stream, revision, signature preservation, repair.

Пример кода Delphi

Следующий эскиз Delphi показывает практическую границу сервиса для этой темы. Оставляйте проверки политики, журналирование и валидацию вне узкого блока вызова продукта, чтобы сценарий было проще тестировать.

procedure SaveCompactIncrementalPdf(const OutputFile: string);
var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := OutputFile;
    Pdf.UseXRefStream := True;
    Pdf.UseObjectStreams := True;
    Pdf.BeginDoc;
    AddRevisionContent(Pdf);
    Pdf.EndDoc;
    CompareObjectStreamProfile(OutputFile);
  finally
    Pdf.Free;
  end;
end;

Производственный чек-лист

  • Запускайте сценарий на пустом файле, обычном клиентском файле и файле худшего случая
  • Открывайте сгенерированный PDF в целевом просмотрщике, валидаторе, принтере или downstream-приложении
  • Записывайте версию продукта, версию профиля, хэш входа, путь вывода, затраченное время и число предупреждений
  • Храните пароли, сертификаты, временные файлы и данные клиентов по явным правилам хранения
  • Добавляйте регрессионные документы, когда клиентский файл выявляет новый граничный случай

Документация по продукту

HotPDF Component

Дополнительные примеры кода

Pdf.BeginIncrementalUpdate('contract-signed.pdf');
Pdf.AddPage;
Pdf.CurrentPage.SetFont('Arial', [], 10);
Pdf.CurrentPage.TextOut(50, 760, 0, 'Addendum recorded 2026-06-11');
Pdf.SaveIncrementalUpdate('contract-updated.pdf');  // appends the delta only
PageCount := Pdf.LoadFromFile('base.pdf');
Pdf.InsertPagesFromDocument(OtherDoc, '1-3', 5);  // pages 1-3 after page 5
Pdf.MovePage(2, 5);
Pdf.SaveLoadedDocument('modified.pdf');
Pdf.LoadFromFile('stamped.pdf');
Pdf.SaveLoadedDocument('compacted.pdf');