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

PDFlibPas: large-PDF merge and split with direct access

losLab PDF Library предоставляет командам Delphi и C++Builder PDF-движок с доступным исходным кодом для настольных, серверных, DLL, ActiveX и Dylib процессов, включая встроенные проверки PDF/A и PDF/UA, подписи PAdES и выбор рендерера без отправки документов во внешний PDF-сервис.

Эта статья предназначена для teams assembling statements, packets, evidence bundles, or page extracts from large customer PDFs. Она рассматривает large-PDF merge and split with direct access как промышленную инженерию документов, а не как одиночный вызов компонента.

Практический риск состоит в том, что merge and split tools often preserve pages but lose bookmarks, named destinations, metadata, page labels, or error evidence when files become large. Поэтому процессу нужны письменный контракт, наблюдаемая диагностика и реалистичные регрессионные файлы.

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

Define what must follow the page. page-range syntax, validation behavior, and empty-range handling / bookmark, destination, page-label, annotation, and form preservation rules

  • page-range syntax, validation behavior, and empty-range handling
  • bookmark, destination, page-label, annotation, and form preservation rules
  • metadata ownership when multiple source documents are merged
  • temporary storage, rollback, progress, and cancellation policy for large files

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

Plan ranges and retained structures up front. The order below keeps the workflow reviewable for Delphi and C++Builder teams.

  1. validate all input files, page ranges, and output destinations before writing
  2. create a page mapping that records source file, source page, and output page
  3. copy or rebuild supporting structures according to the assembly profile
  4. write to a temporary output and validate the result before atomic replacement
  5. save the page map and warnings with the completed job

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

Merge and split evidence for support. Keep these fields with the output or support record.

  • input file list, hashes, sizes, page counts, selected ranges, and output page count
  • page map plus retained or dropped bookmark and destination counts
  • temporary path, cancellation point, rollback result, and elapsed time
  • warnings for damaged pages, unsupported structures, or signature implications

Pages are not the only content being moved

Large-document assembly should consider bookmarks, destinations, annotations, forms, attachments, metadata, page labels, and signatures. Direct access helps performance, but product policy decides which structures are preserved, rebuilt, or dropped.

Regression files worth keeping

Keep more than successful samples. A useful large-PDF merge and split with direct access regression set contains normal files, boundary files, and intentional failure files so the behavior is stable across releases.

  • signed source documents may lose signature trust when pages are extracted
  • bookmarks can point to pages that are removed or reordered
  • forms with shared field names can collide after merge
  • large output files need atomic replacement to avoid partial delivery
  • validate all input files, page ranges, and output destinations before writing
  • create a page mapping that records source file, source page, and output page

Замечания для инженерного ревью по large-PDF merge and split with direct access

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

  • Решение: page-range syntax, validation behavior, and empty-range handling. Точка приложения при реализации: create a page mapping that records source file, source page, and output page. Доказательство приемки: temporary path, cancellation point, rollback result, and elapsed time. Триггер регрессии: large output files need atomic replacement to avoid partial delivery
  • Решение: bookmark, destination, page-label, annotation, and form preservation rules. Точка приложения при реализации: copy or rebuild supporting structures according to the assembly profile. Доказательство приемки: warnings for damaged pages, unsupported structures, or signature implications. Триггер регрессии: signed source documents may lose signature trust when pages are extracted
  • Решение: metadata ownership when multiple source documents are merged. Точка приложения при реализации: write to a temporary output and validate the result before atomic replacement. Доказательство приемки: input file list, hashes, sizes, page counts, selected ranges, and output page count. Триггер регрессии: bookmarks can point to pages that are removed or reordered
  • Решение: temporary storage, rollback, progress, and cancellation policy for large files. Точка приложения при реализации: save the page map and warnings with the completed job. Доказательство приемки: page map plus retained or dropped bookmark and destination counts. Триггер регрессии: forms with shared field names can collide after merge
  • Решение: page-range syntax, validation behavior, and empty-range handling. Точка приложения при реализации: validate all input files, page ranges, and output destinations before writing. Доказательство приемки: temporary path, cancellation point, rollback result, and elapsed time. Триггер регрессии: large output files need atomic replacement to avoid partial delivery
  • Решение: bookmark, destination, page-label, annotation, and form preservation rules. Точка приложения при реализации: create a page mapping that records source file, source page, and output page. Доказательство приемки: warnings for damaged pages, unsupported structures, or signature implications. Триггер регрессии: signed source documents may lose signature trust when pages are extracted
  • Решение: metadata ownership when multiple source documents are merged. Точка приложения при реализации: copy or rebuild supporting structures according to the assembly profile. Доказательство приемки: input file list, hashes, sizes, page counts, selected ranges, and output page count. Триггер регрессии: bookmarks can point to pages that are removed or reordered

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

  • signed source documents may lose signature trust when pages are extracted
  • bookmarks can point to pages that are removed or reordered
  • forms with shared field names can collide after merge
  • large output files need atomic replacement to avoid partial delivery

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

PDFlibPas should sit behind a small service boundary that receives files, streams, profiles, and credentials, then returns output paths, warnings, metrics, and validation status. Важные термины включают merge, split, direct access, page range, bookmark, page map.

Пример кода Delphi

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

procedure MergeLargePdfSet(const ListFile, OutputFile: string);
var
  Pdf: TPDFlib;
begin
  Pdf := TPDFlib.Create;
  try
    RequireSortedInputList(ListFile);
    Pdf.MergeFileListFast(ListFile, OutputFile);
    VerifyMergedPageRanges(OutputFile);
  finally
    Pdf.Free;
  end;
end;

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

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

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

PDFlibPas

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

PageRef := Lib.DAFindPage(Handle, 250);          // page number -> object handle
if PageRef <> 0 then
begin
  Text := Lib.DAExtractPageText(Handle, PageRef, 0);
  Lib.DARenderPageToFile(Handle, PageRef, 5, 150, 'page250.png');
end;
Lib.AddToFileList('Statements', 'jan.pdf');
Lib.AddToFileList('Statements', 'feb.pdf');
Lib.AddToFileList('Statements', 'mar.pdf');
Lib.MergeFileList('Statements', 'q1-statements.pdf');

// Verify the result the cheap way: direct access again
Handle := Lib.DAOpenFileReadOnly('q1-statements.pdf', '');
Writeln('merged pages: ', Lib.DAGetPageCount(Handle));
Lib.DACloseFile(Handle);