以前,當頁首帶有 Word 或 Excel 樣式漸層背景的 PDF 轉譯為影像時,色彩混合處通常會呈現空白的白色矩形。HotPDF 的頁面轉譯器現在支援適用於第 2 類軸向和第 3 類放射狀漸層的 PDF sh(漸層)運算子:它會沿著漸層軸評估漸層的函式並繪製混合色彩,而早期版本則會默默捨棄該運算子並使該區域保持紙張白色。這兩種漸層類型幾乎涵蓋了所有辦公室文件的漸層需求;而網格類型則不支援,本文章將坦白說明該限制的劃分
為什麼 PDF 漸層會轉譯為白盒子?
PDF 漸層是向量結構,而不是轉譯器可以直接傳送的點陣圖。漸層字典(ISO 32000-1 §8.7.4.5)描述了幾何形狀——Coords 陣列中的軸或一對圓——加上色彩函式,且 sh 運算子會在當前裁剪區域上繪製該漸層,這與您在頁面畫布上繪製路徑和填滿時 HotPDF 所呈現的圖形模型相同。HotPDF 的頁面轉譯器逐個運算子地走訪內容資料流,並跳過任何沒有對應程式碼路徑的運算子,以便頁面的其餘部分仍可轉譯。在 2.335.0 版本之前,sh 屬於被跳過的集合:頁首或全頁漸層對輸出沒有任何貢獻,因此背景顯示為白色。檔案本身從未損毀,只是轉譯器對該運算子沒有處理常式,而白盒子正是缺少處理常式時的樣子
漸層背後的函式評估鏈
在評估其函式之前,無法繪製漸層,因此該機制必須首先就位。第 2 類軸向和第 3 類放射狀漸層都帶有一個 /Function,它將沿著漸層的參數位置對應至色彩(ISO 32000-1 §7.10),而 HotPDF 的函式評估器會解析 FunctionType 並對其進行分派。第 2 類指數內插(§7.10.3)計算 C0 + t^N * (C1 - C0) 並進行 Domain 和 Range 限制;第 0 類取樣函式(§7.10.2)讀取 8 位元、16 位元或 32 位元取樣的網格,並透過 Encode 對應表選擇最接近的取樣,這已在我們對第 0 類取樣色彩查表法的深入介紹中詳細說明;第 3 類拼接(stitching)函式(§7.10.4)透過 Bounds 陣列選擇子函式並遞迴其中。第 4 類 PostScript 計算器函式(§7.10.5)則不進行評估——它們會平穩降級為評估失敗而非錯誤色彩,這符合 HotPDF 在整個轉譯路徑中所採取的保守策略。此評估器於 2.334.0 版本中發布,比運算子本身早了一個版本,因為漸層繪製器的效果完全取決於其底層的函式
HotPDF 如何將連續漸層轉換為像素?
HotPDF 使用有限的實心色彩頻帶(bands)來模擬連續的色彩混合。漸層繪製器沿著漸層軸走訪,將其分割為最多 64 個頻帶(當該軸在裝置像素中較短時則更少)、評估每個頻帶參數位置的函式,並以實心筆刷填滿垂直於該軸的矩形。這是在頻帶數量與平滑度之間的權衡:更多的頻帶能更精確地追蹤色彩混合,但填滿成本更高,而 64 是刻意設定的上限。由於頻帶數量也與裝置像素中的軸長度成比例,因此解析度非常重要。在更高的 DPI 下轉譯同一個頁面會拉長該軸,因此短漸層會獲得更多頻帶,其條紋也會變得更柔和,直到達到上限為止
// 漸層離散化器沿著漸層軸使用最多 64 個色彩頻帶,
// 但絕不超過該軸在裝置像素中的長度。在
// 更高 DPI 下轉譯同一個頁面會拉長該軸,因此短漸層
// 會獲得更多頻帶,且漸層條紋會變柔和,直到達到 64 個頻帶的上限。
Thumb := Pdf.RenderLoadedPageToBitmap(PageIndex, 96); // 較粗糙的頻帶
Proof := Pdf.RenderLoadedPageToBitmap(PageIndex, 300); // 最多 64 個頻帶
將漸層頁面轉譯至點陣圖
公用進入點保持不變:RenderLoadedPageToBitmap 接收以 0 為起始的頁面索引和 DPI 值,傳回呼叫端擁有的 24 位元點陣圖,並在失敗時傳回 nil 而非引發異常,因此漸層支援對於您現有的程式碼是透明的。以前將漸層頁首轉譯為空白的頁面,現在會傳回繪製了混合色彩的相同點陣圖,且無需修改 API 即可獲得。唯一需要記住的是擁有權:呼叫端負責釋放傳回的點陣圖。完整的轉譯管道——內容資料流解譯、內嵌字形和頁面快取——已在在 Delphi 中將 PDF 頁面轉譯至點陣圖的指南中介紹
var
Pdf: THotPDF;
Bmp: TBitmap;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('quarterly-report.pdf') > 0 then
begin
// 在 150 DPI 下的第 1 頁(以 0 為起始)。以前
// 轉譯為空白的漸層填滿頁首,現在包含其混合色彩。
Bmp := Pdf.RenderLoadedPageToBitmap(0, 150);
if Assigned(Bmp) then
try
Bmp.SaveToFile('page1.bmp');
finally
Bmp.Free;
end;
end;
finally
Pdf.Free;
end;
end;
同一呼叫也可以作為一個簡單的迴歸防禦。轉譯頁面,在漸層頻帶所屬的位置取樣一個像素,並確認它不再是轉譯器以前退回的紙張白色——這是一個單行檢查,可以擷取是否默默回到了舊有的無操作(no-op)行為
Bmp := Pdf.RenderLoadedPageToBitmap(0, 150);
if Assigned(Bmp) then
try
// 當 sh 運算子進行了繪製時為 True;如果該區域退回為白色則為 False。
HeaderPainted := Bmp.Canvas.Pixels[Bmp.Width div 2, 8] <> clWhite;
finally
Bmp.Free;
end;
HotPDF 不繪製的內容:網格漸層和裁剪邊緣
這四種網格漸層類型不在支援範圍內,文件應提前瞭解這一點。ISO 32000-1 §8.7.4.5.5 至 §8.7.4.5.8 中定義的自由格式 Gouraud 三角形網格(第 4 類)、晶格格式 Gouraud 網格(第 5 類)、Coons 補片網格(第 6 類)和張量積補片網格(第 7 類)均不進行轉譯;使用其中之一的頁面仍可轉譯,只是該區域會保持原樣。還有兩個邊界值得清楚說明。頻帶矩形覆蓋的是漸層的條紋,而不是精確地裁剪到當前的裁剪路徑,因此被遮罩為圓形或不規則形狀的漸層會繪製為其邊界條紋,直到後續版本加入精確的區域裁剪為止。HotPDF 還假設函式輸出為 RGB 或灰階,因此在 CMYK 或特殊色彩空間中建立的漸層是透過模擬而非進行色彩管理。對於大多數 Delphi 和 C++Builder 小組實際處理的文件——報告、發票、對帳單和匯出為 PDF 的簡報投影片——軸向和放射狀幾乎涵蓋了您會遇到的所有漸層,而網格密集的設計打樣則應視為預覽而非打樣
HotPDF 的頁面轉譯器、此處介紹的 sh 運算子支援,以及其底下的第 0/2/3 類函式評估器,均作為適用於 Delphi 和 C++Builder 的 HotPDF 元件 的一部分隨附提供——這是一個無外部 DLL 相依性的原生 VCL 函式庫,在一個套件中涵蓋了 PDF 建立、編輯、文字擷取和頁面轉譯功能