做者:馬健
郵箱:stronghorse_mj@hotmail.com
發佈:2009.09.22
更新:
2012.06.11
針對PdfToy的新進展,更新了相關內容。php
1 引言
2 理論
3 實現
3.1 MRC模型的轉換
3.1.1 單層DjVu
3.1.2 3層DjVu
3.1.3 2層DjVu(彩色文本)
3.2 圖像的轉換
3.2.1 JB2轉JBig2
3.2.2 IW44轉JPEG 2000
3.2.3 JPEG與CCITT G4的轉換
3.3 隱藏文本的轉換
3.4 目錄的轉換
3.5 其餘部分的轉換
4 結論
5 引伸
5.1 用DjVu技術製做PDF
5.2 反向轉換
5.3 PDF瀏覽器限制html
在掃描電子文檔領域,PDF與DjVu各有特點,也都各有一批堅決的支持者,因此網上常常能看到求助實現兩種格式互相轉換的帖子——都但願能轉成本身或別人喜歡的格式。網上提供的解決方案也多種多樣,從最簡單的虛擬打印(PDF與DjVu均有虛擬打印機),到使用專門的工具 (單步)或工具集合(多步)轉換都有。算法
出於興趣,我最近也在這方面進行了一些技術探索,不太重點不在結果自己(我我的一直不主張在不一樣格式之間轉來轉去窮折騰),而在於轉換的過程:但願能從技術角度比較PDF與DjVu的模型與內部數據壓縮算法,儘可能實現無損轉換,同時保持文件長度變化不大。瀏覽器
本文就是上述過程的一個記錄。less
按我我的的理解,DjVu的高壓縮比主要來自如下幾個方面:ide
與ISO 32000-1相對照,其實以上特性在PDF中也有:工具
因此,在理論上,大多數DjVu能夠在轉換成PDF時,作到在文件長度變化不大(變化仍是有,畢竟文件結構方面存在差別)的狀況下,數據無損(JB2->JBig2)或視覺無損(IW44->JPEG 2000)。性能
注意我說的是「大多數DjVu」,由於例外老是存在的。學習
理論說上一大堆,若是沒有一個實際實現,總仍是以爲有點虛。因此我就以FreePic2Pdf的PDF生成引擎爲基礎,加入對DjVu的支持,最終在DjVuToy中實現了DjVu轉PDF功能:一次能夠轉換一本書, 除圖像外還包括多級書籤、隱藏文本,但不包括註釋、縮略圖等。測試
下面分別介紹一下其中幾個關鍵技術的實現原理和方法,及對最終結果的驗證。
前面說過,DjVu的基本圖像模型是ISO/IEC 16485 MRC三層模型,但並不是全部DjVu都湊足了三層,有些只有單層或2層。
下面針對這三種狀況,討論DjVu的MRC到PDF圖像模型的轉換。
單層DjVu其實就是單一的圖像,與PDF中的圖像能夠直接創建對應關係,所以單層DjVu轉PDF不涉及太多模型層面的東西,轉換的時候將整幅圖像插入PDF頁面中便可。
3層DjVu也不復雜,PDF的圖像模型中一樣容許使用蒙板,甚至容許指定蒙板的透明度(權重),所以3層DjVu轉PDF,在模型上也沒有太多的問題,只在於怎麼選擇合適的蒙板表示而已。
最終我選擇了用SMask實現,緣由很簡單:用這種方式產生的PDF在Acrobat中瀏覽時能夠指定背景色 ,即成爲常說的「透明背景PDF」。
這個例子是一個三層結構的DjVu文件及用DjVuToy轉換後的PDF文件,有興趣的能夠比較一下顯示效果。內部數據的比較結果以下:
各位若是有興趣,不妨把這個例子DjVu另存爲單張靜態圖像,能夠看到文件長度急劇膨脹,對照一下將有助於理解我前面說的DjVu高壓縮比的緣由。
DjVu轉PDF的官方轉換軟件Caminova DocumentExpress Enterprise 7.5(簡稱deent75)在轉換多層DjVu的時候,有一個噱頭:轉換出來的PDF帶有圖層控制,能夠在用Acrobat瀏覽的時候,指定顯示前景層或背景層。我我的以爲圖層控制會增長PDF文件的長度,並且支持圖層控制的PDF瀏覽器和會用的人都不多,因此就沒管它。
DjVuToy的噱頭是:轉換出來的PDF是背景透明的,不管是單層仍是多層,用戶在瀏覽的時候均可以指定背景色。
「彩色文本」是DjVu的一個獨門絕技。若是頁面中含有彩色文字,在DjVu中能夠有兩種實現方法(參見Lizardtech公司2005年出版發行的《Lizardtech DjVu Reference DjVu V3》第7.1.3.1節「Foreground Encoding」):
兩種方法相比較,後者的編碼效率要更高一些,顯示時的文字顏色也比較純正,缺點是每一個符號的顏色必須是單一純色,不能出現變化(如漸變色文字)。而前者的適應範圍無疑要更普遍一些,壓縮比問題一般經過縮圖解決,如長寬縮至1/12,則面積僅爲原先的1/144,還沒開始編碼就輕鬆超過1:100的壓縮比。
以我對PDF的瞭解,採用彩色文字的DjVu若是想轉換成PDF,最無損的辦法大概是:把Sjbz數據段拆成「字典」和「頁面描述」兩個部分,字典中的符號封裝成點陣字體嵌入PDF,頁面描述中的 內容轉換成PDF的字符輸出指令,FGbz中的顏色描述則轉換成PDF的前景色設置指令。顯示的時候,按照指定的顏色顯示字符,字符點陣來自內嵌字體。
這種方法好是好,可是其中的複雜性我只是想想就失去了嘗試的勇氣。因此最終仍是偷了個懶:把2層結構轉換成常規3層結構。官方轉換軟件deent75用的也是這個方法,不過DjVuToy比deent75多了一個選擇:能夠選擇轉換時前景層的縮圖比例。
在2層模型轉成3層模型的時候,須要先把彩色前景層還原出來,而後再縮圖成前景層,原蒙板層、背景層則不變,這樣就將2層變成了3層。若是前景層不縮圖,則轉換出來的PDF在視覺效果上與原始DjVu是徹底同樣的,可是文件長度會大增——多出來的前景層是灰度或彩色,不論採用JPEG仍是JPEG 2000壓縮,若是畫面尺寸降不下來,文件長度也就降不下來。
在deent75中,對前景層一概縮圖至原像素長、寬的1/12,而DjVuToy的缺省值與deent75相同,但若是對質量很在乎而對文件長度不在乎,也能夠手工設置縮圖比例。
另外前景層圖像的生成也頗有講究,deent75的生成方法我模仿了好久也沒有模仿出來,如今這個是通過大量實驗獲得的,在文件長度、圖像質量方面不見得比deent75差。
這個部分初看起來彷佛沒啥懸念:把JB2中的字典、頁面描述解碼出來,按照JBig2的要求從新編碼、封裝便可,中間不須要全圖解碼成位圖後再從新分割、聚類。
可是實際作過之後纔會知道,這中間仍是有講究的:若是不對字典進行處理,直接就編碼、封裝,最終的結果大概會比最初的JB2數據流長約20%。其中的緣由我也是看了Adam Langley的jbig2enc才明白:若是字典中的某些符號在頁面描述中屢次出現,能夠把這些符號單獨編成一個字典,那些只出現一次的符號編成另一個字典,這樣能夠減少頁面描述中的索引位數,最終減少整個數據流長度。這種技術沒看到有誰專門命名,姑且稱之爲「字典二次編碼」技術。這種技術對多頁共用字典當然有影響, 對單頁獨享字典也有影響。
除了上述字典二次編碼技術外,JBig2的算術編碼效率也對最終數據流長度有影響,不過這部分太複雜了,不是通常人能搞定的。
對最終編碼結果的驗證則很簡單:
這樣的驗證其實說明一件事:對於採用JB2壓縮的單層DjVu,能夠用DjVuToy無損轉換成PDF,文件長度也差很少。
另外JB2與JBig2的類似性也不是偶然的,在AT&T的Patrick Haffner、Leon Bottou、Yann Lecun與Lizardtech公司的Luc Vincent合著的論文《A General Segmentation Scheme For DjVu Document Compression》第2章中,對JB2算法的來歷進行了介紹:
The mask image is encoded with a new bi-level image compression algorithm called JBZ or DjVuBitonal. It is a variation on AT&T's proposal to the emerging JBIG2 standard. The basic idea of JB2 is locate individual shapes on the page (such as characters), and use a shape clustering algorithm to find similarities between shapes. Shapes that are representative of each cluster (or in a cluster by themselves) are coded as individual bitmaps with a method similar to JBIG1.
看來不只名字類似,JB2與JBig2追到根子上還有血緣關係,不過彷佛JBig2後來又發展出了一些新花樣,而JB2就此頹廢了——所託非人啊!
我本人的數學基礎不太好,對小波分析更是望而生畏,因此沒有研究是否可能像JB2轉JBig2那樣,在不解碼成位圖的狀況下實現直接轉換,而是採用了一個偷懶的笨辦法:先把IW44解碼成位圖,根據解碼先後的數據流長度能夠算出壓縮比,而後按照這個壓縮比,再把位圖壓縮成JPEG 2000。這裏面的關鍵就是:JPEG 2000壓縮容許指定壓縮比,保證壓縮出來的數據流長度在指定的範圍內。
對最終編碼結果的驗證也很簡單:
若是有誰對小波比較精通,不妨對IW44和JPEG 2000進行一下深刻研究,我總以爲這兩者是能夠直接轉換的——研究有成果了別忘記通知我一聲。
上面的JB二、IW44驗證說明:對於3層DjVu,在用DjVuToy轉換成PDF後,模板層確定是無損的,前景層、背景層視覺無損,文件長度差別不大。
對於2層DjVu,因爲須要補充前景層,轉換後文件長度增長會明顯,前景層縮圖形成的影響在某些狀況下也是視覺可查的。
按照《Lizardtech DjVu Reference DjVu V3》的規定,DjVu中的蒙板層除JB2壓縮外,還能夠採用CCITT G4壓縮,其Chunk ID爲Smmr;前景層、背景層除IW44外,還容許採用JPEG壓縮,其Chunk ID分別爲FGjp、BGjp。
因爲這兩種壓縮算法的壓縮效率與JB二、IW44相差太多,所以採用這兩種壓縮算法的DjVu文件在現實中根本沒有,我本身測試用的文件也是用軟件特地製做出來的。
PDF自己支持CCITT G四、JPEG壓縮,所以採用這兩種壓縮的圖像能夠無損轉換至PDF——CCITT G4可能還須要從新編碼,JPEG圖像整個嵌進去便可。
DjVu的設計初衷是針對掃描圖像,但也提供隱藏文本功能,方便對文檔內容進行檢索、複製等。
DjVu中的隱藏文本經過OCR得到,帶隱藏文本的DjVu習慣上稱爲「雙層DjVu」,這實際上是從「雙層PDF」沿用過來的——用掃描圖像製做的PDF,也能夠經過OCR生成隱藏文本。
在DjVu轉PDF的過程當中,若是DjVu已經有隱藏文字,天然但願可以直接轉過去,不用再OCR。但其中涉及到DjVu與PDF的一個本質區別。
DjVu的設計目的從未變過,就是針對掃描圖像,文字不過是輔助,所以DjVu中的文字是真正的「隱藏」文字,只有文字的編碼(utf-8)、文字的位置,但不含任何字體信息,所以理論上是顯示不出文字的,除非再額外指定字體。
PDF中的文字則與圖像並列,顯示出來是正常的,隱藏起來不過是特例。所以在PDF中,文字除了有編碼、顯示位置、顯示比例外,還要有字體信息。因此在將DjVu中的隱藏文本轉換成PDF時,麻煩就麻煩在字體上。
PDF中的字體能夠是內嵌字體,也能夠是外掛字體。具體哪一種更優,各人見解不一樣。我本身是比較傾向於外掛字體。
PDF中對外掛字體有特殊規定,要求全部PDF瀏覽器均支持的14種標準字體中,就有9種是針對西歐拉丁語系(Latin 1),對CJK(中、日、韓)則規定了額外的標準字體,是否支持由各瀏覽器自行決定。Acrobat若是裝了亞洲語言包,是能支持Adobe的CJK標準字體的。UnicornViewer是中國人開發的,對CJK的支持就更不用說了。
換句話說,若是採用外掛字體,其實只有Latin 1(西歐11國)和CJK(簡、繁、日、韓)才能保證平臺通用性,其它語言,如俄語,理論上說能夠指定Windows的TrueType字體做爲外掛字體,但其平臺通用性沒法保證。
在用deent75轉換DjVu成PDF時,對於隱藏文字也只針對Latin 1和CJK的外掛字體轉換。DjVuToy在隱藏文本轉換方面徹底學自deent75,其位置與deent75的差別在小數點後第4位——DjVuToy我以爲到小數點後第4位 已經足夠,deent75以爲還應該保留更多的位數。
DjVuToy在模仿deent75的基礎上,也作了一些改進:
總之,有些東西是用出來的。
目錄在PDF中稱爲Outline,在DjVu中稱爲Bookmark、Contents,其實就是在瀏覽的時候,左側顯示出來的分級大綱。
DjVu中的目錄其實比PDF簡單得多,並且不能實現對跳轉位置的精細控制:在PDF中,經過點擊目錄項既能夠跳轉到某一頁,也能夠跳轉到頁中的某個位置,而DjVu只能跳轉到頁,這點和PDG的目錄差很少。
DjVuToy轉換DjVu目錄的時候就是直轉,即將DjVu中的utf-8轉換成PDF的Unicode,頁碼也照轉。不過我也偷了點懶:DjVu中的目錄容許跳轉到某個文件或某個URL,DjVuToy對這些狀況就無視了。
在DjVu中,還有註釋、縮略圖等內容,這些在PDF中都有對應,理論上說在轉換成PDF也應該能轉過去,不過我看官方的deent75也沒管這些,因此我也都無視了,反正這些東東對我來講也根本碰不到,不值得花時間。
綜上所述,大多數DjVu在轉換成PDF時,能夠在文件長度變化不大的狀況下,作到數據無損(JB2轉JBig2)或視覺無損(IW44轉JPEG 2000),並能將隱藏文本、目錄等一塊兒轉換過去,前提是轉換的方法和工具得當。
從這一點上說,「DjVu格式的壓縮比高於PDF格式」的觀點實際上是不成立的——在「格式」上PDF也能夠實現DjVu的高壓縮比,所以兩者的差別不在於「格式」,而在於把靜態圖像轉換成最終「格式」的工具和方法。
目前常見的PDF製做工具,包括Acrobat,在將靜態圖像轉換成PDF時,多半採用「嵌入」的方式,即將整個靜態圖像數據流甚至文件嵌入PDF文件中,不進行進一步的處理 (如按MRC模型分層)。這種方法的好處是技術簡單、實現方便、圖像能夠徹底無損,缺點是常常有人抱怨這樣作出來的PDF文件比DjVu大得多。
而從前面的描述來看,DjVu的高壓縮比與它的「分層結構、按需編碼」有直接關係,而這是能夠複製到PDF中來的。所以我認爲若是想提升掃描版PDF的壓縮率,能夠在PDF製做軟件上進行改進:引入商業DjVu製做軟件的內核或引擎,對須要轉換成PDF的掃描圖像進行分層,而後按照分層結果選擇最有效的圖像壓縮算法。即把上面說的「圖像->DjVu->PDF」過程簡化成「圖像->PDF」,中間這一步在PDF製做軟件內部悄悄完成了。
固然,若是不嫌麻煩,或者有OCR的技術積累,也能夠本身去作分層的開發,但最終結果是同樣的。其實在我第一次看到用luratech公司的產品製做出來的高壓縮比PDF時,我就懷疑他們是這麼幹的。這也是促使我去寫這篇文章的緣由之一。 而目前的deent75,也容許用戶指定生成的結果文件是DjVu仍是PDF,若是選擇PDF,就直接實現了圖像轉分層PDF。
在討論完DjVu轉PDF後,一個很天然的問題就是:這樣轉換出來的PDF,能不能再轉回DjVu?
我對這個問題的回答是:看你想怎麼轉。最簡單的辦法固然是直接打印到DjVu虛擬打印機上,或者找一個現成的PDF2DjVu軟件,喜歡折騰的也能夠先把PDF轉圖片,而後圖片轉DjVu。
不過既然前面說了半天數據格式轉換,那我們的思惟仍是別太發散,仍是按照一樣的思路:能不能從PDF文件數據流裏抽取圖像數據流,及層次描述,而後儘可能無損地轉換回DjVu?個人回答是:不必定。理由以下:
所以,我至今也只實現了把PDF中的JBig2導出爲DjVu,但不敢去試PDF->DjVu,並且建議各位也別閒來無事轉着玩,否則哪天忽然後悔了可沒地兒買藥去。
反向轉換的研究雖然進行得不完全,不過也產生了其餘的副產品:在研究過程當中,我感受將來採用JPEG 2000壓縮的PDF會增長,所以在UnicornViewer中專門增強了對這方面的支持,而且我名下全部與PDG相關的軟件,均開始支持「名爲PDG實爲JPEG 2000的文件」:若是PDF中的圖片實在轉不回DjVu,乾脆導出成圖片看算了。
按照我前面說的方法和工具轉換出來的PDF採用了JBig二、JPEG 2000壓縮,前者要求Acrobat 5以上版本,後者要求Acrobat 6以上版本的瀏覽器才能正常顯示。好在如今主流的Acrobat版本最低也是7。其餘常見的PDF瀏覽器中,PDF-XChange支持這兩種格式沒有問題,Foxit須要專門的插件,CajViewer則不支持。我本身的UnicornViewer沒有問題,在JPEG 2000方面還進行過專門強化,比Acrobat8的兼容性更好。