HotXLS 可在 Delphi 與 C++Builder 中,不透過 Excel、也不透過 PDF 印表機驅動程式,直接將活頁簿或單一工作表匯出為 PDF/A。在 TXLSPDFExport 上設定 UsePDFA 並選擇一個設定檔,匯出的檔案就會帶有內嵌 sRGB ICC 描述檔作為輸出意圖、XMP 中繼資料中的 pdfaid 識別區塊,以及符合該一致性等級的 PDF 版本標頭
這項需求通常來自文件保存政策,而不是開發者本身。財務報表、實驗室結果、法規申報文件,以及任何公部門必須保存數十年的資料,都必須以五十年後仍能完全相同呈現的格式儲存,而這正是 PDF/A(ISO 19005)存在的目的。試算表是一個即時計算的結果;試算表的封存副本則必須是這個結果的固定畫面
什麼讓一份 PDF 成為封存用 PDF?
三項要求承擔了大部分工作。檔案必須自我完備,因此其使用的每種字型都必須內嵌,且不得參照任何外部資源。色彩必須明確無歧義,這代表要有一個輸出意圖,指名檔案製作時所依據的色彩空間。而且檔案必須能自我識別,透過 XMP 中繼資料宣告部件編號與一致性等級
HotXLS 三項都具備。sRGB 描述檔以三分量的串流物件內嵌,並以 DeviceRGB 作為替代色彩空間,由一個 GTS_PDFA1 輸出意圖參照,其條件與識別碼皆指名 sRGB IEC61966-2.1。XMP 封包帶有 pdfaid 部件與一致性項目。描述檔位元組是編譯進函式庫內,而不是在執行期載入,因此不需要額外的部署步驟,也不會因為缺少某個檔案,就讓封存匯出悄悄退化成一般匯出
uses
lxHandleX, lxPDF;
var
Book: TXLSXWorkbook;
Exporter: TXLSPDFExport;
begin
Book := TXLSXWorkbook.Create;
Exporter := TXLSPDFExport.Create;
try
if Book.Open('quarterly-results.xlsx') <> 1 then
Exit;
Exporter.UsePDFA := True;
Exporter.PDFAProfile := xlsPdfA2b; // ISO 19005-2 B 級
Exporter.DocumentLanguage := 'en-GB';
Exporter.TagMode := xlsPdfTagsAutomatic;
if Exporter.SaveAsPDF(Book, 'quarterly-results-archive.pdf') <> 1 then
raise Exception.Create('archival export failed');
finally
Exporter.Free;
Book.Free;
end;
end;
該選擇哪一種設定檔?
此設定檔列舉涵蓋 PDF/A-1、PDF/A-2 與 PDF/A-3,每一種都有無障礙變體與基本變體。實務上的差異比清單列出的還要小
B 級(基本變體)保證視覺外觀可重現。A 級則新增結構與語意要求,主要是標記結構樹與明確定義的閱讀順序,讓文件能被輔助科技存取。第 2 部分放寬了第 1 部分的部分限制,並允許使用物件串流與 JPEG 2000;第 3 部分則進一步允許任意內嵌檔案,這正是電子發票格式用來在人類可讀頁面旁附帶機器可讀 XML 的方式
對於封存試算表而言,PDF/A-2b 是務實的預設選擇:它廣泛受各封存機構接受,不需要 A 級對儲存格網格施加的標記規範,也允許使用精簡結構,讓 200 頁的活頁簿匯出檔不至於過度膨脹。當封存還必須以附件形式攜帶原始資料時,可選擇第 3 部分,匯出工具透過 AddAttachment 支援此需求
多數人會踩到的字型規則
PDF/A 檔案繪製的每一個字形,都必須來自內嵌字型。這是原本正確的匯出結果卻無法通過驗證的最常見單一原因,而且這種失敗模式相當隱晦:檔案在產生它的那台機器上看起來完全正常,因為那台機器上已經安裝了那個字型
HotXLS 會為所使用的字型內嵌 TrueType 子集,但當某個字型無法解析時,仍存在一條 Base 14 備援路徑,而 Base 14 備援依定義就是不會內嵌的。若要產生封存用輸出,請明確設定一個 Unicode 字型檔案,讓備援路徑永遠不會被觸發。子集化與備援鏈結的運作機制,說明於TrueType 字型子集化一文;務實的做法是在一台未安裝你公司字型的機器上測試這個匯出結果
匯出工具保證了什麼,又沒有保證什麼
在這裡精確比聽起來有信心更重要。匯出結果會產生 PDF/A 所需的識別機制——輸出意圖、內嵌 ICC 描述檔、pdfaid 中繼資料、對應的版本標頭——並讓文字經由內嵌路徑處理。但它不會對自己的輸出執行完整驗證,因此不會強制檢查規範中的每一項禁令,例如透明度規則、特定附註類型的規則,以及選用內容(optional content)的規則
對試算表匯出而言,這些結構很少出現,這也是實務成功率偏高的原因。但偏高不等於保證,對於真正的封存流程而言,正確的架構是先匯出,再用獨立工具進行驗證,並把驗證失敗視為流程錯誤,而不是警告。針對 PDF 文件的類似責任劃分,說明於PDF/A 預檢驗證一文
版面配置也是封存保真度的一部分
一份技術上符合規範、但視覺上無法閱讀的封存試算表,等於沒有完成它真正的任務。頁面設定在封存匯出中的份量,比在日常列印中更重,因為日後不會再有人能重新排版它
三項設定物有所值。「配合頁寬」可避免典型的失敗情況:一張 14 欄寬的表格被拆成七頁、每頁只有兩欄。重複標題列讓每一頁單獨檢視時都能讀懂。明確的列印範圍則能排除擺在真正資料右側的工作備註。完整的列印與頁面設定控制項,涵蓋於保護、頁面設定與列印一文
// 適合封存的頁面設定,於匯出前套用
Sheet := Book.Sheets[0];
Sheet.PageLandscape := True;
Sheet.FitToWidth := 1;
Sheet.FitToHeight := 0; // 高度方向依需要延伸多少頁
Sheet.SetPrintArea('A1:N480');
Sheet.PrintTitleRows := '$1:$3';
// 中繼資料也屬於封存的一部分
Book.Title := 'Quarterly results 2026 Q2';
Book.Author := 'Finance';
首次批次執行前的檢查清單
確認檔案能自我識別:不需要解壓縮任何東西,只要用文字編輯器開啟 PDF,尋找 pdfaid 部件與一致性項目,以及 GTS_PDFA1 輸出意圖。確認字型:檢查文件中每一種字型是否都回報為已內嵌。確認外觀:把匯出的頁面與一份紙本列印結果比對,因為一個把文字悄悄縮到四級字的「配合頁面」設定,即使符合規範也毫無用處
接著對具代表性的樣本執行一套獨立驗證工具,並保留驗證報告。愈來愈多封存機構不只要求檔案本身,還要求驗證證明,而在匯出當下就產生這份證明,遠比多年後再重建它便宜得多。關於日常、非封存用途的匯出路徑與其渲染選項,請參見工作表 PDF 匯出一文
封存匯出、頁面設定與背後的渲染引擎,在 Delphi 與 C++Builder 中同屬一套函式庫;完整功能清單請見HotXLS Delphi 試算表元件頁面