THotPDF Preflight Report Methods

Syntax

type
  THPDFPreflightFormat = (pfText, pfJSON, pfHTML, pfCSV);

function CreatePreflightReport(
  const SourceFile: TFileName;
  const Password  : AnsiString = ''): AnsiString; overload;
function CreatePreflightReport(
  const SourceFile: TFileName;
  const Password  : AnsiString;
  const Format    : THPDFPreflightFormat): AnsiString; overload;
procedure SavePreflightReport(
  const SourceFile: TFileName;
  const ReportFile: TFileName;
  const Password  : AnsiString = ''); overload;
procedure SavePreflightReport(
  const SourceFile: TFileName;
  const ReportFile: TFileName;
  const Password  : AnsiString;
  const Format    : THPDFPreflightFormat); overload;
function ValidatePDFVT(
  const SourceFile: TFileName;
  out Report      : AnsiString): Boolean;
function ValidatePDFVT(
  const SourceFile: TFileName;
  const Password  : AnsiString;
  out Report      : AnsiString): Boolean;
procedure EmbedPreflightReportInPDF(
  const SourceFile: TFileName;
  const TargetFile: TFileName);
procedure EmbedPreflightReportInPDF(
  const SourceFile: TFileName;
  const TargetFile: TFileName;
  const Password  : AnsiString);
function LoadAndValidatePreflightReport(
  const EmbeddedFile  : TFileName;
  out OriginalReport: AnsiString;
  out CurrentReport : AnsiString): Boolean;
function LoadAndValidatePreflightReport(
  const EmbeddedFile  : TFileName;
  const Password      : AnsiString;
  out OriginalReport: AnsiString;
  out CurrentReport : AnsiString): Boolean;
function ComparePreflightReports(
  const ReportA: AnsiString;
  const ReportB: AnsiString): AnsiString;
function RepairPDFFromPreflightReport(
  const SourceFile: TFileName;
  const TargetFile: TFileName;
  out RepairsApplied: AnsiString): Boolean;
function RepairPDFFromPreflightReport(
  const SourceFile: TFileName;
  const TargetFile: TFileName;
  const Password  : AnsiString;
  out RepairsApplied: AnsiString): Boolean;
function AggregatePreflightReports(
  const Reports: array of AnsiString): AnsiString;
type
  THPDFPreflightProfile = record
    DisableChecks  : AnsiString;
    DisableWarnings: AnsiString;
    DisableHints   : Boolean;
  end;
function LoadPreflightProfile(
  const ProfileFile: TFileName): THPDFPreflightProfile;
function ApplyPreflightProfile(
  const Report : AnsiString;
  const Profile: THPDFPreflightProfile): AnsiString;
function ValidatePreflightProfile(
  const Profile: THPDFPreflightProfile;
  out UnknownNames: AnsiString): Boolean;
function GetBuiltInPreflightProfile(
  const Name: AnsiString): THPDFPreflightProfile;
procedure SavePreflightProfile(
  const Profile    : THPDFPreflightProfile;
  const ProfileFile: TFileName);
function CreatePreflightReportWithProfile(
  const SourceFile : TFileName;
  const Password   : AnsiString;
  const ProfileFile: TFileName;
  const Format     : THPDFPreflightFormat): AnsiString;
function MergePreflightProfiles(
  const A, B: THPDFPreflightProfile): THPDFPreflightProfile;
function DiffPreflightProfiles(
  const A, B  : THPDFPreflightProfile;
  out OnlyInA: AnsiString;
  out OnlyInB: AnsiString): Boolean;
procedure EmbedPreflightReportAsXMP(
  const SourceFile: TFileName;
  const TargetFile: TFileName);
procedure EmbedPreflightReportAsXMP(
  const SourceFile: TFileName;
  const TargetFile: TFileName;
  const Password  : AnsiString);
function ConvertPreflightReportToVeraPDFStyle(
  const Report: AnsiString): AnsiString;

說明

CreatePreflightReport 讀取 input PDF,並回傳包含輕量 structural checks 的 text report。password overloads 會對支援的 encrypted PDFs 使用既有 password-aware load path。SavePreflightReport 會將相同 report 寫入 target text fileCreatePreflightReport 讀取輸入 PDF,回傳 帶有輕量結構檢查的文字報告。密碼 overload 對支援的加密 PDF 走既有的密碼感知載入路徑 SavePreflightReport

ValidatePDFVT 執行聚焦的 PDF/VT 驗證, 只有在必要的標記與結構都存在時才回傳 True。回傳的文字報告會檢查 pdfvtid:GTS_PDFVTVersion XMP 宣告、PDF/VT 中繼資料 命名空間、PDF/VT 修改日期與 xmp:ModifyDate 是否相符、PDF/X 基礎標記、加密缺席、PDF/X 輸出意圖、 catalog 的 DPartRoot、DPartRootNode、 NodeNameList、文件部分是否存在、可載入頁數, 以及頁面層級的 DPart 涵蓋率。PDF/VT 與 XMP 日期 屬性可寫成元素文字,或寫成 rdf:Description 上的 RDF 屬性

The report checks the PDF header, EOF marker, whether the final %%EOF 標記是否接近檔案結尾、最後一個 startxref 偏移量,以及該偏移量指向 xref 表 還是 xref stream、%%EOF 與 startxref 標記 的數量、修訂標記的平衡與最終標記順序、trailer 或 XRef stream 標記、可載入頁數、 加密狀態、catalog、頁面樹、頁面物件標記、 MediaBox、資訊字典參照、根參照、 間接物件數、間接物件定義數、最高物件 編號、重複物件編號數、物件編號唯一性、catalog 物件數、頁面樹物件數、頁面物件數、頁面樹 宣告的頁數、頁面樹數量與可載入頁數的一致性、頁面 物件與可載入頁數的一致性、stream 與 endstream 的平衡、stream /Length 項目的涵蓋率、xref 表數量、 xref 子區段數量、 xref 表項目數、xref free 與使用中項目數、格式錯誤的 xref 列數、xref 列有效性、xref 對物件編號的涵蓋率、 xref stream 數量、object stream 數量、trailer 數量、trailer /Size、trailer /Size 是否涵蓋 最高物件編號、trailer /Root 與 /Info 間接參照、被參照物件是否已定義、 trailer /Root 是否指向 catalog 物件、 trailer /ID 陣列項目數與成對結構,以及 trailer /Root、/Info、/ID、 /Encrypt 是否存在、 估計的增量更新次數、線性化狀態、已載入的 頁面框、表單欄位數、資源字典數、字型資源數、 內嵌字型程式數(/FontFile、 /FontFile2、/FontFile3)、影像 XObject 數、 Form XObject 數、ColorSpace 資源數、註解數與 widget/連結註解子計數,以及 FlateDecode、 DCTDecode、CCITTFaxDecode、 JBIG2Decode、LZWDecode、ASCIIHexDecode、 ASCII85Decode、RunLengthDecode 與 JPXDecode 的 filter 鏈使用計數

The Format overload 接受 pfText(預設的 純文字路徑,與舊版 overload 位元組穩定相容)、 pfJSON(CI 友善的 JSON 文件)、 pfHTML(儀表板就緒、自包含的 HTML 報告,內嵌 CSS 並依嚴重性著色資料列),或 pfCSV (適合試算表的中繼資料、檢查、提示、警告 與摘要資料列)。JSON 輸出把項目分組到 input、size、pdfVersion 與 xrefStyle 頂層欄位,加上 checks、 info、hints、warnings 陣列 以及帶有 failed、warnings、result 值的 summary 物件。每個檢查、提示與警告都帶有穩定的 命名空間 ruleId 與結構化的 location 物件 location 一律包含邏輯 scope 與斜線分隔的 path,可能包含關聯的 PDF key,並在報告能定位精確座標時附上 objectNumber、pageIndex 或 byteOffset。CSV 輸出 使用穩定的表頭 category,name,status,value,spec,診斷有對應標準條款時,spec 內含 ISO 參考文字。內建的 JSON 編碼器會跳脫 "、\

Each checks、hints 與 warnings 項目帶有選用的 spec 欄位,標明診斷所針對的 ISO 條款(例如 trailer 相關檢查對應 ISO 32000-1 sec 7.5.5, PDF/A 與 JavaScript 互斥警告對應 ISO 19005-1 sec 6.6.2)。此對應涵蓋到 v2.122.0 為止報告輸出的每個檢查、提示與 警告。描述 pfJSON 輸出結構的正式 JSON Schema (draft 2020-12)發布於 Docs/preflight-schema.json, 下游消費端可在解析前先驗證輸出 規則 ID 使用穩定格式 hotpdf.preflight.<category>.<rule-name>

EmbedPreflightReportInPDF 會把來源 PDF 的副本寫到 TargetFile,並在最後一個 %%EOF 之後 以 PDF 風格的註解列(每列以 %  開頭)附加 舊式文字格式的預檢報告。PDF 讀取器會忽略附加的位元組,因為它們位於 物件圖之外;但封存工作流程、文字編輯器與 grep

LoadAndValidatePreflightReport extracts the report that EmbedPreflightReportInPDF previously appended, re-runs the current preflight algorithm against the source bytes preceding the embedded comment block, and compares the InputFingerprint values. The function returns True when both fingerprints match, indicating the embedded report still describes the file as it exists on disk When validation fails, callers can inspect OriginalReport and CurrentReport to diff what changed.

ComparePreflightReports 會為兩份 reports 輸出 unified-diff-like body。共有行以前置兩個空格顯示,只存在於 ReportA 的行以前置 - 顯示,只存在於 ReportB 的行以前置 + 顯示。演算法針對 CreatePreflightReport 產生、line order 具決定性的 well-formed key/value output 調校;它不是 general-purpose LCS implementation,但能為大多未變的典型 reports 產生精簡且可讀的 diffsComparePreflightReports 會為兩份報告輸出類似 unified diff 的本文。共有的列以兩個空格為前綴, ReportA 獨有的列以 -  為前綴, ReportB 獨有的列以 +  為前綴。演算法針對 CreatePreflightReport 產生的格式良好鍵值輸出調校

RepairPDFFromPreflightReport applies a conservative subset of byte-level repairs to a damaged PDF: it drops trailing bytes that follow the final %%EOF marker, and appends a missing %%EOF when one is not present anywhere. The function returns True when at least one repair was applied; RepairsApplied lists the repairs as one line per change. Object-graph repairs (rebuilding xref tables, patching stream lengths, fixing trailer dictionaries) are intentionally out of scope because such fixes can make a partially-recoverable file less recoverable; use a dedicated PDF recovery tool for deeper damage.

AggregatePreflightReports 接受 per-file reports array,並產生單一 batch summary。array 中每個 entry 都會解析其 Input、Size 與 Summary fields;aggregate 會為每個檔案輸出一行,並彙總 passed、failed 與 warning reports 數量、total bytes scanned,以及 overall result counts。適合處理 PDF 目錄且最後需要單一精簡摘要的 CI pipelines 與 shell loopsAggregatePreflightReports 接收每檔報告的陣列, 產出單一批次摘要。陣列中的每個項目都會被解析出 Input、 Size 與 Summary

LoadPreflightProfile and ApplyPreflightProfile let callers tailor the report output without re-running the analysis. The profile file uses an INI-style format with three optional sections: [disable-checks] lists check names to suppress; [disable-warnings] lists warning names to suppress; and [options] accepts hints=false to suppress every Hint line. After filtering, the Summary line is recomputed so the suppressed entries no longer contribute to the Failed and Warnings totals; the rest of the report passes through unchanged.

ValidatePreflightProfile 會走訪已載入 profile 的 DisableChecks 與 DisableWarnings lists,並回報目前 preflight implementation 無法識別的任何名稱。這可用來偵測針對較新或較舊 HotPDF version 撰寫的 profile files;否則因名稱不符合任何輸出的 check 或 warning,可能會靜默地沒有停用任何項目ValidatePreflightProfile 會走訪已載入 profile 的 DisableChecks 與 DisableWarnings

GetBuiltInPreflightProfile returns ready-to-use profile records for common workflows. Recognized names (case-insensitive): default / '' returns an empty profile; compact disables every Hint line for shorter reports; silent-actions disables every PDF 1.7 sec 12.6.4 action warning plus EmbeddedFile and RichMedia, intended for workflows that intentionally embed multimedia or interactive actions and do not want the preflight report to flag them. Unknown names also return an empty profile.

SavePreflightProfile writes a THPDFPreflightProfile record back to an INI file in the same format that LoadPreflightProfile consumes The two functions are exact inverses for well-formed profiles, so callers can build a 'load preset, tweak, save' workflow: P := GetBuiltInPreflightProfile('compact'), edit P.DisableChecks, then SavePreflightProfile(P, 'tuned.ini') for later reuse.

CreatePreflightReportWithProfile 是 one-stop convenience wrapper,組合既有 CreatePreflightReport、LoadPreflightProfile、ApplyPreflightProfile 與 format converters;因此已有 source PDF、optional password、profile file 與 target format 的呼叫端,可用單一呼叫取代四段串接。傳入空 ProfileFile 會略過 profile stepCreatePreflightReportWithProfile 是一站式的 便捷包裝,組合既有的 CreatePreflightReport、 LoadPreflightProfile、 ApplyPreflightProfile 與格式轉換器;手上已有來源 PDF、選用密碼、 profile 檔與目標格式的呼叫端,可以用單一呼叫 取代串接四個方法。傳入空的 ProfileFile

MergePreflightProfiles 回傳兩個 profile 去除重複後的 聯集:DisableChecks 與 DisableWarnings 會收集兩個輸入中的名稱, DisableHints

DiffPreflightProfiles reports the structural difference between two profiles. Returns True when they are equivalent; otherwise False with OnlyInA and OnlyInB filled with newline-separated lines of the form check:<name>, warn:<name>, or option:hints=false describing which entries are exclusive to each side.

EmbedPreflightReportAsXMP is an archival-friendly variant of EmbedPreflightReportInPDF: it writes a copy of the source PDF with the preflight report appended as a PDF-style comment block whose payload is XMP / RDF (xmlns:hotpdf="http://www.loslab.com/hotpdf/preflight/") Each report line becomes a hotpdf:<name> element with severity carried as an attribute on check rows XMP-aware tools that scan a file for xpacket markers can surface the embedded report; PDF readers continue to ignore the appended bytes because they fall outside the object graph. This is intentionally not a spec-compliant XMP integration: the XMP payload is not referenced from the catalog /Metadata entry, so XMP readers that only follow the catalog reference will not see it.

ConvertPreflightReportToVeraPDFStyle 會將 HotPDF preflight report 塑造成遵循 veraPDF validation output 大致輪廓的 JSON document,包含 top-level profile field、含 itemDetails / taskResult / validationResult 的 jobs array,以及 validationResult.details 下的 ruleViolations array。這是 HotPDF-styled,而非與 veraPDF wire-compatible;目標是讓已消費 veraPDF JSON 的 downstream tooling 只需最少 field-name remapping 即可適應 HotPDF output,而不必重新學習完全不同的 data layoutConvertPreflightReportToVeraPDFStyle 會把 HotPDF 預檢報告整理成一份 JSON 文件,大致遵循 veraPDF 驗證輸出的輪廓:頂層有 profile 欄位、含 itemDetails / taskResult / validationResult 的 jobs 陣列,以及 validationResult.details 之下的 ruleViolations 陣列。它採 HotPDF 風格,而非與 veraPDF 線上相容;目標是讓 已經消費 veraPDF JSON 的下游工具,只需最少限度地改欄位名 就能改吃 HotPDF 輸出,不必重新學一套完全不同的資料布局 每個 violation 帶有相同的穩定 ruleId 與 結構化 location

Example

var
  PDF: THotPDF;
begin
  PDF := THotPDF.Create(nil);
  try
    PDF.SavePreflightReport('Input.pdf', 'PreflightReport.txt');
    PDF.SavePreflightReport('Encrypted.pdf', 'EncryptedReport.txt', 'user-password');
    PDF.SavePreflightReport('Input.pdf', 'PreflightReport.json', '', pfJSON);
    PDF.SavePreflightReport('Input.pdf', 'PreflightReport.html', '', pfHTML);
    PDF.SavePreflightReport('Input.pdf', 'PreflightReport.csv', '', pfCSV);
    PDF.EmbedPreflightReportInPDF('Input.pdf', 'Input-with-report.pdf');
    if not PDF.LoadAndValidatePreflightReport(
      'Input-with-report.pdf', OriginalReport, CurrentReport)
    then
      WriteLn('Embedded preflight report no longer matches the source.');
  finally
    PDF.Free;
  end;
end;

請參閱