在 uses 子句加入 FPdfMerge,即可使用 TPdfNavigationMergeHelper.MergeFilesWithNavigation,或明確指定目的文件呼叫全域 MergePdfFilesWithNavigation 函式
輔助功能先暫存原生頁面匯入、重建階層大綱、合併具名目的地、重新對應頁面連結,再獨立重新開啟結果,確認後才取代呼叫端文件
pmnPreserve 保留來源階層;pmnGroupBySource 為每個來源檔案加入同名標題
保留標題、父子關係、樣式、色彩、展開分支、URI 動作與已解析的內部頁面目的地;選定、重複與重新排序的頁面對應到第一次匯入位置,指向省略頁面的目的地則成為標題
插入頁面時,既有目的端大綱會位移;擷取導覽與原生頁面匯入期間,來源檔案保持開啟並拒絕寫入共用
僅支援遇錯停止的合併;已簽署目的端、不支援的大綱動作與加密後處理會遭拒絕並提供錯誤報告,失敗或取消時保留呼叫端文件
此 API 保留既有原生表單策略;需要進階 AcroForm 欄位衝突與資源處理時,請使用 FPdfFormMerge
PreserveNamedDestinations 與 PreservePageLinks 均預設為 True;將任一選項設為 False,會略過該部分額外導覽處理
具名目的地同時從舊式目錄 /Dests 字典及 /Names/Dests 名稱樹讀取,包含階層樹、間接陣列及含有 /D 的目的地字典;兩種形式定義相同鍵值時,名稱樹的值優先
結果使用平衡的 /Names/Dests 樹,保留目的端中不相關的名稱樹,例如 /EmbeddedFiles;此輔助功能不匯入來源中與目的地無關的名稱樹
鍵值保留原始 PDF 字串位元組,包括 UTF-16BE 編碼;完整保留檢視模式及參數,例如 /FitH null 與 /XYZ null 34 null
| 策略 | 行為 |
|---|---|
pndReject | 來源鍵值若已存在於目的端,會拒絕整個交易 |
pndRename | 預設策略保留無衝突名稱,為衝突名稱加上 DestinationPrefix,其預設為 Imported_;後續衝突使用可重現的前綴,例如 2_Imported_Shared |
pndNamespace | 每個來源鍵值都加上 DestinationPrefix、從一起算的來源索引及底線,例如 Imported_1_Shared;剩餘衝突再加入可重現的數字前綴 |
DestinationPrefix 必須包含 1 到 256 個可列印 ASCII 字元;鍵值使用 UTF-16BE 時,前綴插入在 BOM 之後
使用 /Dest 或單一 /A /GoTo 動作的內部連結註解會改寫為明確目的地,因此具名連結目標在衝突重新命名後仍然正確
插入頁面時,既有連結的擁有者頁面及目標會位移;重複匯入頁面的每次出現都得到獨立連結註解,其內部目標則對應到目標頁面第一次選取的出現位置
目標頁面被省略的目的地會從具名目的地樹移除;受影響連結會移除 /Dest 或 GoTo 動作,保留註解及其其他屬性
URI 連結維持完整;使用 /Next 的串接連結動作會遭拒絕,因為重新對應動作鏈尚不在此輔助功能範圍內
格式錯誤或循環的目的地樹、不可用物件參照及重複的名稱樹鍵值都會拒絕交易;失敗、取消或超出預算時,呼叫端文件維持原樣
預設上限為 10,000 個大綱項目、深度 128、1,048,576 個標題字元、10,000 個具名目的地、100,000 個頁面連結及 256 MiB 文件位元組;文件位元組上限不得超過 MaxInt
啟用額外目的地或連結處理時,可設定的最大深度為 256,具名目的地上限不得超過 65,536,頁面連結上限不得超過 1,000,000;來源擷取也將原始鍵值位元組限制為 1 MiB
合併的具名鍵值使用獨立位元組預算,等於 MaxTitleCharacters;每個來源會先在設定的預算內擷取,再依選取頁面篩選
PreservedNamedDestinationCount 計算最終具名目的地,RenamedNamedDestinationCount 計算依選定策略變更的匯入鍵值,RemovedNamedDestinationCount 計算未解析或省略的具名目標
RemappedPageLinkCount 計算既有與匯入連結的最終內部目的地,RemovedPageLinkCount 計算移除的內部目的地;同時含 /Dest 與 GoTo 的連結,會為各目的地各計一次
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;
FPdfCompress 提供 CapturePdfNavigation 與 WritePdfNavigation,供自行管理頁面匯入與稀疏 PDF 修訂的呼叫端使用
TPdfNavigationNamedDestination.NameKey 包含原始 PDF 鍵值位元組;頁碼為絕對值且從一起算,零表示未解析的目標
TPdfNavigationPageLink.PageNumber 識別擁有者頁面;AnnotationIndex 是所有原始註解中從零起算的序號,LinkIndex 則僅計算連結註解的序號
寫入器以 LinkIndex 識別連結,將各註解複製並設定最終頁面擁有者,寫入提供的頁面目標與確切目的地後綴;呼叫端必須提供匯入所需的完整對應
寫入器要求來源與輸出為不同串流,文件未加密也未簽署;相同串流遭參數檢查拒絕時會保留來源,其他失敗則會清空獨立輸出串流
這些串流函式不匯入頁面,也不取代使用中的 TPdf 文件;完整導覽合併請使用較高階的交易式函式
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;