PDFium Delphi Component Docs

Navigation merging within a transaction

Include FPdfMerge in the uses clause for TPdfNavigationMergeHelper.MergeFilesWithNavigation, or pass a destination document explicitly to the global MergePdfFilesWithNavigation function

Before replacing the caller's document, the helper stages native page imports, rebuilds outline hierarchies, combines named destinations, remaps page links and reopens the result independently

Use pmnPreserve for the source hierarchy, or pmnGroupBySource to add a heading bearing each source filename

The merge retains titles, parent relationships, styles, colours, expanded branches, URI actions and resolved internal page destinations; selected, repeated or reordered pages point to the first imported occurrence, whilst destinations on omitted pages become headings

Inserting pages shifts existing destination outlines; source files remain open without write sharing while navigation and native page imports are captured

Merging must stop on error; signed destinations, unsupported outline actions and encrypted postprocessing are refused with an error report, and neither failure nor cancellation alters the caller's document

Native form handling follows the existing policy; advanced AcroForm collision and resource handling belongs to FPdfFormMerge

Named destinations and internal page links

Both PreserveNamedDestinations and PreservePageLinks start as True; changing either to False omits its additional navigation-processing step

The reader handles the legacy catalog /Dests dictionary and the /Names/Dests name tree, including nested trees, indirect arrays and destination dictionaries with /D; the name-tree entry wins if both define the same key

Output has a balanced /Names/Dests tree and retains other destination name trees such as /EmbeddedFiles; the helper does not import unrelated source trees

Keys keep their original PDF string bytes, including UTF-16BE; exact view modes and parameters survive, including /FitH null and /XYZ null 34 null

PolicyBehaviour
pndRejectIf a source key is already present in the destination, the entire transaction is refused
pndRenameThe default retains unique names and adds DestinationPrefix to conflicting names; its default is Imported_, with further conflicts resolved deterministically, for example 2_Imported_Shared
pndNamespaceEach source key gains DestinationPrefix, its one-based source index and an underscore, for example Imported_1_Shared; any remaining conflict receives a deterministic numeric prefix

DestinationPrefix needs 1 to 256 printable ASCII characters; for UTF-16BE keys the prefix follows the BOM

An internal link with /Dest or one /A /GoTo action is rewritten to an explicit destination, so collision renaming does not break a named link target

Page insertion shifts existing link owners and targets; every repeated import gets its own link annotation, whose internal targets point to the first selected occurrence of the target page

A named destination on an omitted page is removed from the tree; affected links lose their /Dest or GoTo action but retain the annotation and its remaining properties

URI links are retained; /Next action chains are refused because this helper does not currently remap chained actions

The transaction rejects malformed or cyclic destination trees, unresolved object references and duplicate name-tree keys; failed, cancelled or over-budget operations leave the caller's document intact

Budgets and reporting

Defaults permit 10,000 outline items, depth 128, 1,048,576 title characters, 10,000 named destinations, 100,000 page links and 256 MiB of document bytes; the document-byte limit cannot exceed MaxInt

With extra destination or link processing enabled, depth cannot exceed 256, named destinations cannot exceed 65,536 and page links cannot exceed 1,000,000; capturing a source also limits raw key data to 1 MiB

Combined named keys have their own byte allowance equal to MaxTitleCharacters; each source is captured within the configured allowances before page selection is applied

PreservedNamedDestinationCount counts final named destinations, RenamedNamedDestinationCount counts imported keys renamed by the policy, and RemovedNamedDestinationCount counts omitted or unresolved named targets

RemappedPageLinkCount counts final internal destinations in existing and imported links; RemovedPageLinkCount counts those removed, and a link with both /Dest and GoTo counts separately for each destination

Public declarations

type
  TPdfMergeNavigationPolicy= (pmnPreserve, pmnGroupBySource);
  TPdfMergeNamedDestinationPolicy= (pndReject, pndRename, pndNamespace);

  TPdfNavigationMergeOptions= record
    NativeOptions: TPdfBatchMergeOptions;
    NavigationPolicy: TPdfMergeNavigationPolicy;
    MaxOutlineItems: Integer;
    MaxOutlineDepth: Integer;
    MaxTitleCharacters: Integer;
    MaxDocumentBytes: Int64;
    PreserveNamedDestinations, PreservePageLinks: Boolean;
    NamedDestinationPolicy: TPdfMergeNamedDestinationPolicy;
    DestinationPrefix: string;
    MaxNamedDestinations, MaxPageLinks: Integer;
    class function Default: TPdfNavigationMergeOptions; static;
  end;

  TPdfNavigationMergeReport= record
    Succeeded: Boolean;
    Cancelled: Boolean;
    ImportedSourceCount: Integer;
    ImportedPageCount: Integer;
    PreservedOutlineCount: Integer;
    RemovedDestinationCount: Integer;
    SourceGroupCount: Integer;
    PreservedNamedDestinationCount, RenamedNamedDestinationCount: Integer;
    RemovedNamedDestinationCount, RemappedPageLinkCount, RemovedPageLinkCount: Integer;
    ErrorMessage: string;
  end;

  // The caller's document is replaced only after the complete staged result
  // has been independently reopened and its outline destinations checked
  TPdfNavigationMergeHelper= class helper for TPdf
    function MergeFilesWithNavigation(const Sources: TPdfBatchMergeSources;
      const Options: TPdfNavigationMergeOptions;
      out Report: TPdfNavigationMergeReport): Boolean;
  end;

function MergePdfFilesWithNavigation(Destination: TPdf;
  const Sources: TPdfBatchMergeSources;
  const Options: TPdfNavigationMergeOptions;
  out Report: TPdfNavigationMergeReport): Boolean;

Processing streams directly

FPdfCompress provides CapturePdfNavigation and WritePdfNavigation for applications managing their own page imports and sparse PDF revisions

TPdfNavigationNamedDestination.NameKey holds the original PDF key bytes; page numbers are absolute and one-based, and zero identifies an unresolved target

TPdfNavigationPageLink.PageNumber is the owner page; AnnotationIndex is its zero-based position amongst all original annotations, whilst LinkIndex counts link annotations alone

The writer uses LinkIndex to find each link, clones the annotation for its final owner page and writes the supplied targets with their exact destination suffixes; provide every mapping your imports require

Writing requires separate source and output streams and an unsigned, unencrypted document; rejection of identical streams preserves the source, whilst other failures empty the separate output

Stream functions neither import pages nor replace a live TPdf document; complete navigation merging should use the higher-level transactional function

function CapturePdfNavigation(Source: TStream; MaxNamedDestinations,
  MaxPageLinks, MaxDepth: Integer; out Names: TPdfNavigationNamedDestinations;
  out Links: TPdfNavigationPageLinks; out ErrorText: string): Boolean;

function WritePdfNavigation(Source, Output: TStream;
  const Names: TPdfNavigationNamedDestinations;
  const Links: TPdfNavigationPageLinks; ReplaceNamedDestinations: Boolean;
  out ErrorText: string): Boolean;