這是關于該主題的第二部分。如果你還沒有閱讀第一部分,請先閱讀,以便理解“繞組規則”的問題。
快速回顧一下:HTML5 只支持 Non-Zero(非零)繞組規則,而 PDF 同時支持 Non-Zero 和 Even-Odd(奇偶)兩種規則。
這意味著我們必須對使用了 Even-Odd 填充規則的圖形做些處理,否則它們在 HTML5 中可能無法正確顯示。
為了演示這個問題,我會用以下這個例子:
看上去只是個紅色的圓?
我第一次看到的時候也是這么想的。直到我把填充改為描邊模式,才意識到它實際上是什么。
為了幫助理解發生了什么,我們再來看一張圖,加上箭頭,顯示路徑的繪制方向。
我們首先想到的是,可能需要改變圖形的繪制方式。最直接的想法就是改變路徑的方向,也就是“轉換”成 Non-Zero 繞組規則的等價圖形。
交替使用順時針和逆時針方向可行嗎?
值得一試,看看會發生什么。反正只需要一分鐘時間試一下。
結果證明,這其實挺頭疼的。如果只是用?lineTo?畫個方框還好說,但涉及貝塞爾曲線的話,情況就復雜得多。
如果你只是簡單地反轉繪制指令的順序,就會得到像這樣的問題:
控制點的順序會影響曲線的繪制方式。那么,我們能否也反轉控制點的順序呢?
哦——這樣也不太對。我們使用的是?bezierCurveTo,它的意思是:從當前位置(由上一個繪圖命令決定)開始,通過兩個控制點繪制一段曲線,終點是我們指定的位置。這就意味著我們還必須反向地重新組織控制點和終點的順序,這樣曲線才能按正確的方式被繪制出來。
做對了之后,我們就能反轉路徑方向,讓圖形按預期繪制出來:
那么問題解決了嗎?沒有。
對于我們的“禁止通行”標志來說,或許可以這樣處理——我們可以手動控制路徑的順序和方向。但在現實世界中,這種做法不能適用于通用場景。我們不可能為每個具體的 PDF 文件都手動處理,我們需要的是一套普適的代碼邏輯,讓它能應對任何 PDF 文件。
這也就意味著交替改變路徑方向并不能真正解決問題。比如看一下我們禁止通行標志在這種方式下的效果:
我的下一個想法是:用背景色填充被遮擋的區域。但這也行不通,因為路徑的繪制順序還是關鍵。即使我們把兩個 “D” 字母填充為白色,當外面的圓形被填充時,它還是會把我們之前的工作覆蓋掉。
而且如果兩個形狀只是部分重疊,那么只有重疊部分才需要“未填充”。更關鍵的是,這些“未填充”的部分是真正的透明區域,如果你用背景色填充,就會失去透明性,導致我們無法在后面放其他圖層,比如顯示“你不可以做這件事”的提示。
那怎么辦?
如果不能改變繪制順序,也不能改變路徑方向,也不能通過填色偽裝,我們還能怎么改造圖形,讓它在使用 Non-Zero 繞組規則時正常顯示?
或許我們可以非常巧妙地將圖形切割成許多小塊,然后分析每一塊該如何繪制,再分別填充這些小塊。
像這樣:
_____
| ? __|__
|__|__| ?|
? ?|_____|
?_____
| ? __|
|__|
? ? __
? ?|__|
? ? ? ?__
? ? __| ?|
? ?|_____|
?
但這就太復雜了。對于我們的需求來說,有點大材小用了。而且,這種做法計算量大,會降低我們轉換器的性能。更現實的是,我也沒那么聰明,寫不出來這樣的算法。
其實從我開始研究這些形狀開始,腦海里就一直有一個小聲音在說:
“要不,我們干脆把這些圖形輸出成圖片得了?”
確實,這樣做是可行的,但并不理想。實際上,使用 Non-Zero 和 Even-Odd 繞組規則繪制圖形,最終渲染結果真正不同的情況并不多。
所以,如果我們每次遇到 Even-Odd 繪制規則就輸出成圖片,那會產生大量沒必要的圖像文件。
這也不理想,因為矢量圖形本身非常好用:縮放不會失真,從 PDF 轉到 HTML5 非常快速,占用空間也遠遠小于圖片。
那我們還能怎么辦?
我們只能妥協。
最合理的做法就是:設定一套規則,只有當圖形符合某些特定條件時,才把它輸出為圖片。
其余情況我們仍然盡可能用原始的路徑繪制方式進行呈現。這樣,在保持性能和顯示效果之間取得一個平衡。
我們的主頁:PDF 轉 HTML5、Java 圖像庫、Java PDF SDK - IDRsolutions
?