标签:
作者:马健
邮箱:stronghorse_mj@hotmail.com
发布:2009.09.22
更新:
2012.06.11
针对PdfToy的新进展,更新了相关内容。
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浏览器限制
在扫描电子文档领域,PDF与DjVu各有特色,也都各有一批坚定的支持者,所以网上经常能看到求助实现两种格式互相转换的帖子——都希望能转成自己或别人喜欢的格式。网上提供的解决方案也多种多样,从最简单的虚拟打印(PDF与DjVu均有虚拟打印机),到使用专门的工具 (单步)或工具集合(多步)转换都有。
出于兴趣,我最近也在这方面进行了一些技术探索,不过重点不在结果本身(我个人一直不主张在不同格式之间转来转去穷折腾),而在于转换的过程:希望能从技术角度比较PDF与DjVu的模型与内部数据压缩算法,尽量实现无损转换,同时保持文件长度变化不大。
本文就是上述过程的一个记录。
按我个人的理解,DjVu的高压缩比主要来自以下几个方面:
与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进行一下深入研究,我总觉得这二者是可以直接转换的——研究有成果了别忘记通知我一声。
上面的JB2、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。
由于这两种压缩算法的压缩效率与JB2、IW44相差太多,因此采用这两种压缩算法的DjVu文件在现实中根本没有,我自己测试用的文件也是用软件特意制作出来的。
PDF本身支持CCITT G4、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采用了JBig2、JPEG 2000压缩,前者要求Acrobat 5以上版本,后者要求Acrobat 6以上版本的浏览器才能正常显示。好在现在主流的Acrobat版本最低也是7。其他常见的PDF浏览器中,PDF-XChange支持这两种格式没有问题,Foxit需要专门的插件,CajViewer则不支持。我自己的UnicornViewer没有问题,在JPEG 2000方面还进行过专门强化,比Acrobat8的兼容性更好。
标签:
原文地址:http://www.cnblogs.com/stronghorse/p/4913393.html