比较原始图像数据和PDF中的图像数据,结果见表1.1。表1.1中各种“解码器”的解释见本文后续的“PDF支持的图像格式”部分,“PDF中的图像数据”各栏中的数据来自开源的PdfView。如果您有兴趣查看PDF文件内部细节,建议用UltraEdit-32,仅看PDF文件结构 用PdfView足矣。表1.1 从ACDSEE打印图像到Acrobat PDF虚拟打印的结果
原始图像 | PDF中的图像数据 | ||||||
序号 | 说明 | 宽×长 (象素) |
图像解码器 | 文件长度 (字节) |
PDF解码器 | BitsPerComponent /ColorSpace |
数据流长度 (字节) |
01 | 黑白TIFF | 1728×1103 | CCITT G3 | 50,401 | CCITT G4 | 1/ICCBased | 54,329 |
02 | 黑白TIFF | 3315×2334 | CCITT G4 | 35,518 | CCITT G4 | 1/ICCBased | 36,110 |
03 | 彩色JPEG格式TIFF | 512×384 | DCTDecode | 24,428 | DCTDecode | 8/ICCBased | 21,753 |
04 | 灰度JPG | 445×600 | DCTDecode | 34,167 | FlateDecode | 8/Indexed | 200,404 |
05 | 彩色JPG | 1024×768 | DCTDecode | 102,776 | DCTDecode | 8/ICCBased | 71,540 |
06 | 16级灰度GIF | 800×1199 | LZWDecode | 124,738 | FlateDecode | 4/Indexed | 128,925 |
07 | 256色GIF | 130×129 | LZWDecode | 8,408 | FlateDecode | 8/Indexed | 6,990 |
08 | 黑白PNG | 32×32 | FlateDecode | 164 | CCITT G4 | 1/ICCBased | 41 |
09 | 2色彩色PNG | 32×32 | FlateDecode | 112 | FlateDecode | 1/ICCBased | 21 |
10 | 256级灰度PNG | 600×905 | FlateDecode | 289,059 | FlateDecode | 8/Indexed | 286,947 |
11 | 16级灰度PNG | 720×1053 | FlateDecode | 74,322 | FlateDecode | 4/Indexed | 74,943 |
12 | 24位色PNG | 350×560 | FlateDecode | 72,107 | FlateDecode | 8/ICCBased | 79,351 |
13 | 15位色BMP | 260×235 | 未压缩 | 122,266 | DCTDecode | 8/ICCBased | 5,783 |
14 | 16色BMP | 940×20 | RLE | 8,134 | FlateDecode | 4/Indexed | 2,868 |
图像文件总长度(字节) | 946,600 |
PDF文件总长度(字节) | 989,431 |
注1. 图像01.tif经ACDSEE转成PDF后,图像物理表示的高度变成2206,原因后面会加以解释。
注2. 对于索引色(Indexed)图像,“数据流长度”仅包含图像数据流长度,不包含索引(调色板)数据流长度。严格说来这会造成一些误差,但影响不大。以下各表与此相同,不再特殊说明。
从表1.1可以看出,对于ACDSEE发送过来的数据流,Acrobat PDF虚拟打印机进行如下处理:
这种处理带来的问题是:
为了确认是否所有软件在使用虚拟打印机转换PDF时,均会对JPG图像进行再压缩,我进行了第二个试验:在Word 2003中插入用例1中的13张图像(Word 2003不支持03.tif),每张图像前面再插入一点文字(图像编号),然后打印到Acrobat PDF虚拟打印。限于篇幅,这里不列举具体结果(用例1是公开的,Word 2003、Acrobat也不难找,想要较真的人可以自己动手试一下),仅说明结果:
从转换结果的对比来看,Word和ACDSEE的打印结果在TIFF、JPG、PNG方面存在较大差距:
综上所述,对于基于虚拟打印原理实现的图像转PDF工具,可能会存在如下问题:
直接将图像嵌入PDF的转换软件工作原理与基于虚拟打印机的转换软件不同,其工作过程为:
为了测试图像嵌入式转换工具的效果,我将与表1.1相同的图像文件(用例1), 用ACDSEE 8.0 (Build 39)的Create PDF Wizzard转换成PDF,结果见表1.2。
原始图像 | PDF中的图像数据 | ||||||
序号 | 说明 | 宽×长 (象素) |
解码器 | 文件长度 (字节) |
解码器 | BitsPerComponent /ColorSpace |
数据流长度 (字节) |
01 | 黑白TIFF | 1728×1103 | CCITT G3 | 50,401 | DCTDecode | 8/DeviceGray | 905,917 |
02 | 黑白TIFF | 3315×2334 | CCITT G4 | 35,518 | DCTDecode | 8/DeviceGray | 693,129 |
03 | 彩色JPEG格式TIFF | 512×384 | DCTDecode | 24,428 | DCTDecode | 8/DeviceRGB | 34,496 |
04 | 灰度JPG | 445×600 | DCTDecode | 34,167 | DCTDecode | 8/DeviceGray | 59,338 |
05 | 彩色JPG | 1024×768 | DCTDecode | 102,776 | DCTDecode | 8/DeviceRGB | 129,655 |
06 | 16级灰度GIF | 800×1199 | LZWDecode | 124,738 | DCTDecode | 8/DeviceRGB | 319,743 |
07 | 256色GIF | 130×129 | LZWDecode | 8,408 | DCTDecode | 8/DeviceRGB | 6,706 |
08 | 黑白PNG | 32×32 | FlateDecode | 164 | DCTDecode | 8/DeviceGray | 936 |
09 | 2色彩色PNG | 32×32 | FlateDecode | 112 | DCTDecode | 8/DeviceRGB | 896 |
10 | 256级灰度PNG | 600×905 | FlateDecode | 289,059 | DCTDecode | 8/DeviceGray | 185,845 |
11 | 16级灰度PNG | 720×1053 | FlateDecode | 74,322 | DCTDecode | 8/DeviceGray | 206,121 |
12 | 24位色PNG | 350×560 | FlateDecode | 72,107 | DCTDecode | 8/DeviceRGB | 38,468 |
13 | 15位色BMP | 260×235 | 未压缩 | 122,266 | DCTDecode | 8/DeviceRGB | 8,209 |
14 | 16色BMP | 940×20 | RLE | 8,134 | DCTDecode | 8/DeviceRGB | 22,018 |
图像文件总长度(字节) | 946,600 | PDF文件总长度(字节) | 2,619,592 |
从表1.2中可以看出,ACDSEE 8.0 (Build 39)的Create PDF Wizzard对图像的转换原则是:
看来ACSEE对它的JPG转换引擎还真不是一般地有信心!但从表1.2所列数据看,这种转换也不是没有问题:
ACSEE的转换插件效果很令我失望,为了比较其它嵌入式工具的转换效果,我又用用例1测试了verypdf的Image2Pdf v1.7,转换结果见表1.3。
原始图像 | PDF中的图像数据 | ||||||
序号 | 说明 | 宽×长 (象素) |
解码器 | 文件长度 (字节) |
解码器 | BitsPerComponent /ColorSpace |
数据流长度 (字节) |
01 | 黑白TIFF | 1728×1103 | CCITT G3 | 50,401 | CCITT G4 | 1/DeviceGray | 41,638 |
02 | 黑白TIFF | 3315×2334 | CCITT G4 | 35,518 | CCITT G4 | 1/DeviceGray | 34,981 |
03 | 彩色JPEG格式TIFF | 512×384 | DCTDecode | 24,428 | DCTDecode | 8/DeviceRGB | 32,815 |
04 | 灰度JPG | 445×600 | DCTDecode | 34,167 | DCTDecode | 8/DeviceGray | 34,167 |
05 | 彩色JPG | 1024×768 | DCTDecode | 102,776 | DCTDecode | 8/DeviceRGB | 102,776 |
06 | 16级灰度GIF | 800×1199 | LZWDecode | 124,738 | RunLengthDecode | 4/Indexed/DeviceRGB | 206,880 |
07 | 256色GIF | 130×129 | LZWDecode | 8,408 | RunLengthDecode | 8/Indexed/DeviceRGB | 13,380 |
08 | 黑白PNG | 32×32 | FlateDecode | 164 | FlateDecode/PNG | 1/DeviceGray | 91 |
09 | 2色彩色PNG | 32×32 | FlateDecode | 112 | FlateDecode/PNG | 1/Indexed/DeviceRGB | 21 |
10 | 256级灰度PNG | 600×905 | FlateDecode | 289,059 | FlateDecode/PNG | 8/DeviceGray | 288,582 |
11 | 16级灰度PNG | 720×1053 | FlateDecode | 74,322 | FlateDecode/PNG | 4/Indexed/DeviceRGB | 74,063 |
12 | 24位色PNG | 350×560 | FlateDecode | 72,107 | FlateDecode/PNG | 8/DeviceRGB | 71,954 |
13 | 15位色BMP | 260×235 | 未压缩 | 122,266 | DCTDecode | 8/DeviceRGB | 8,707 |
14 | 16色BMP | 940×20 | RLE | 8,134 | DCTDecode | 8/DeviceRGB | 20,890 |
图像文件总长度(字节) | 946,600 | PDF文件总长度(字节) | 942,458 |
从表1.3看,Image2Pdf对图像数据的处理要比ACDSEE的PDF创建插件智能得多:
其它图像转PDF的软件我还试过一些,不过基本与以上几种工具类似,都可能因为对图像数据流重新压缩而产生一些问题,差别只在问题的多与少、严重与不严重:
这里说的阅读顺畅性问题,是指:
对于第一个问题,目前没有什么好的解决方案。对于第二个问题,可能的解决方案包括:
这里说的“特殊图像格式”,其实主要就是TIFF格式。在常见的图像格式中,JPG、GIF、PNG、BMP等都有严格的格式规定,可以发挥的余地不多。但是对于TIFF来说,由于标准本身希望能够包容尽可能多的东西,但是对实现细节没有给出具体的规定,所以各家软件生成的TIFF文件五花八门,令人头疼。
以我提供的测试用例2为例,这个其实是支持TIFF文件最权威的开源项目libtiff 3.7.1版所带测试图片,不过去掉了一张caspian.tif(该图片共3通道,单通道采样位数高达64位浮点数,我的32位真彩显示器单通道采样位数只有8位整数,显示不了这么高级的图片)。但仅凭剩下的这些图片,已经可以难倒包括verypdf的Image2Pdf在内的一大批图像转PDF软件,就算是ACDSEE这样“专业”的图像浏览器,5.0.1版在看这些图像时也会出现比例失调(fax2d.tif、g3test.tif)、看不了(quad-tile.tif)、颜色失真(smallliz.tif、zackthecat.tif)等问题;8.0版虽然修正了上述问题,但又出现新的问题:看dscf0013.tif时颜色失真。
其实这些文件还算好,毕竟是libtiff组织提供的,至少它自己的源代码还能解出来。但在我接触到的国内专业扫描外包公司中,大多数公司提供的TIFF文件只要采用了有损压缩,多半就连libtiff也解不开,ACDSEE更是想都不用想。有些甚至连专门显示TIFF文件的Microsoft Office Document Imaging(微软Office 2003所带附件之一)都解不开。
偏偏由于工作需要,我必须和这些怪异TIFF文件打交道。我想到的出路包括:
除TIFF外,PNG文件也是一种可能会造成潜在麻烦的格式。但是与TIFF不同,PNG的麻烦不在于文件格式本身或数据压缩算法,而在于它丰富的色彩表示:PNG支持灰度、索引、彩色、Alpha通道彩色图像,并且色深除低端的1、2、4、8位外,还支持16位色深。有兴趣又喜欢较真的人,可以到libpng下载一份libpng源代码,里面的contrib\pngsuite文件夹下就包含了一堆图片,专门用于测试软件对PNG色彩支持的能力。
从我测试的结果看,软件在处理PNG图像时可能出现的问题包括:
综上所述,目前图像转PDF工具普遍存在一些共性的问题,包括图像数据流重新压缩造成的问题、生成的PDF文件的阅读顺畅性问题、对特殊图像格式的支持问题等。为了更好地理解这些问题,并找到解决办法,下面先简单介绍一下PDF中与图像相关的基本概念。
事先声明:本部分所有内容均来自Adobe公司发布的《PDF Reference 5th edition》, 说白了就是我看这份文档时做的笔记的一部分,所以看起来可能有点无头无尾,各位看得懂就看,看不懂就去看《PDF Reference 5th edition》原文吧。
在PDF文件中,图像点阵信息以压缩数据流的形式存在,PDF通过过滤器(filter)对数据流解码。在《PDF Reference 5th edition》中,共介绍了十种过滤器,其中与图像相关的如表2.1所示。
过滤器名称 | 对应压缩算法通称 | 对应图像格式 | 压缩类型 | 说明 |
LZWDecode | LZW | GIF、TIFF | 无损 | 通常用于索引色(调色板)图像 |
FlateDecode | ZIP | PNG、TIFF | 无损 | 除图像外,也用于文本压缩 |
RunLengthDecode | RLE | BMP、TIFF | 无损 | 通常用于单色图像 |
CCITTFaxDecode | G3/G4 | TIFF | 无损 | 专为黑白图像研发的高效压缩算法 |
JBIG2Decode | JBIG2 | JBG | 无损 | 专为黑白图像研发的高效压缩算法 |
DCTDecode | JPEG | JPG、TIFF | 有损 | 用于256级灰度、24位真彩自然图像 |
JPXDecode | JPEG2000 | J2K、JP2 | 有损/无损 | JPEG的最新标准,压缩比与质量并重 |
从表2.1看,其实对大多数常见图像格式,都可以将原数据流直接嵌入PDF文件,不需要再重新编码。当然某些数据,如JPG文件中的注释、PNG文件的文件头/文件尾,在PDF文件中没用,可以先剔除再将剩余部分嵌入PDF文件。而对于TIFF文件,需要针对具体压缩算法,将真正图像数据抽取出来再嵌入PDF文件。
直接使用原始数据流而不再重新编码,不仅能够节省图像转换成PDF的时间,而且对于有损压缩,可以避免因为反复压缩而造成图像质量的衰减。但是对于GIF格式的LZW压缩来说,情况有点复杂:由于Unisys公司声称对LZW算法拥有专利权,导致很多软件,包括大名鼎鼎的xpdf在内,放弃 对LZW的支持,改用开源的Flate压缩算法。Flate其实是Winzip等软件使用的ZIP压缩算法的另外一个名字。《PDF Reference 5th edition》中对这两种算法的描述如下(黑体效果是我自己加的):
Because of its cascaded adaptive Huffman coding, Flate-encoded output is usually much more compact than LZWencoded output for the same input. Flate and LZW decoding speeds are comparable, but Flate encoding is considerably slower than LZW encoding.
由于上文中黑体部分的描述,及诸多公司、组织卷入与Unisys的专利纠纷,因此在我见到的图像转PDF工具中,没有使用LZW压缩算法的,都宁愿将用LZW压缩的GIF图像解码后再压缩成Flate数据流。这种转换在多数情况下能获得更好的压缩比,但例外总是有的(所以上文用的词是usually,而不是always),如用例1中的06.gif,LZW就比ZIP有效得多,这样的图片我还有几张,不过限于篇幅和空间,就不节外生枝了。
对于LZW和Flate压缩,PDF还支持预报器(Predictor),预报器表示根据图像的某些特征,先对图像进行某些预处理后再对处理结果进行压缩,以获取更高的压缩比。在《PDF Reference 5th edition》中定义的预报器见表2.2。小于10的预报器称TIFF预报器,源自libtiff;10以上的称PNG预报器,源自libpng。因此如果PDF文件中定义图像的物理表示时使用了Predictor属性,多半可以猜到原始图像的格式。 在表3.1和表1.3中,为了更好地进行比较,采用PNG预报器的Flate解码器均标注为FlateDecode/PNG。
预报器值 | 含义 |
1 | No prediction (the default value) |
2 | TIFF Predictor 2 |
10 | PNG prediction (on encoding, PNG None on all rows) |
11 | PNG prediction (on encoding, PNG Sub on all rows) |
12 | PNG prediction (on encoding, PNG Up on all rows) |
13 | PNG prediction (on encoding, PNG Average on all rows) |
14 | PNG prediction (on encoding, PNG Paeth on all rows) |
15 | PNG prediction (on encoding, PNG optimum) |
一幅图像在PDF文件中通常用一个XObject对象表示(某些TIFF图像可能要用多个对象表示),这个对象描述图像的原始象素点阵信息,因为这些点阵信息由产生图像的设备本身的物理性质(如扫描仪的DPI、 数码相机的有效象素数等)决定,因此在这里称为图像的物理表示,在《PDF Reference 5th edition》中又称为采样表示(Sample Representation)。
要描述图像的物理表示,需要提供下列信息:
以用例1为例,在ACDSEE 8 PDF创建插件转换的PDF中,用如表2.3所示的XObject定义第二 幅图像(数据来自PdfView,右侧双斜杠后面是我自己加的注释):
|
PDF中的每个对象均有一个ID(编号),通过对象ID,可以对对象本身进行引用。如一个LOGO图像可能作为背景出现在每一个页面上,在每一页中没有必要都包含这个LOGO图像的实际数据,只要引用这个LOGO图像的ID即可。这样无疑可以提高PDF文件的存储效率。上例中图像的对象ID就是9。
前面说的图像的物理表示是用象素点来表示图像,但是如果直接按照象素点对图像进行显示、打印,可能会出现问题。以用例1中的第二 幅图像为例,象素点阵为3315×2334,如果在分辨率为96 DPI的显示器上显示,尺寸是34.5英寸×24.3英寸(1英寸=2.54厘米,实际英寸数=象素数÷DPI,如3315÷96=34.5英寸),而在分辨率为300 DPI的打印机上打印,打出来只有11.1英寸×7.8英寸,这显然与PDF要求的“在任何平台上均可获得相同的效果”不符。因此在用物理表示定义出图像的象素点阵后,在实际需要显示图像的地方,不仅要给出图像物理表示的对象ID,还需要给出图像的逻辑表示,包括:
这种物理与逻辑表示的分离,可以带来一些好处:
具体到PDF文件格式上,在一个页面上显示一幅图像,除了前面说过的图像的物理表示对象外,还需要定义页面(Page)对象,然后在Page对象中:
Contents属性通常定义一个六元组,表示为[a, b, c, d, e, f],则从图像物理坐标(x, y)映射为逻辑坐标(x', y')的映射关系可以表示为如下矩阵运算:
┌ | a | b | 0 | ┐ | |||
[x' y' 1] = [x y 1] × | │ | c | d | 0 | │ | 式 2.1 | |
└ | e | f | 0 | ┘ |
或表示为如下解析表达式:
x' = ax + cy + e | 式 2.2 | ||||||
y' = bx + dy + f |
从《计算机图形学》知识可知,式2.1、式2.2中参数a、d分别为x、y向比例系数,实现从物理尺寸到逻辑尺寸的映射;c、b为旋转系数,表示图像显示时的旋转角度;e、f为平移系数,表示图像到页面左上角的偏移量。
以用例1为例,在ACDSEE 8 PDF创建插件转换的PDF中,用如表2.4所示的结构定义第二页。
|
内容对象7中定义了图像对象的逻辑表示,如表2.5所示。
|
从表2.5的六元组参数看,ACDSEE 8 PDF创建插件用一种很偷懒的方法构造该六元组:直接用图像的物理象素尺寸作为逻辑尺寸。由于屏幕DPI通常为96 DPI,而PDF为72 DPI,这种偷懒造成的后果就是图像在PDF Reader中按照“实际大小”显示时,看起来会比在ACDSEE中按照“完整大小”显示更大一些。精确一点说,这张图片在PDF中的“实际大小”达到了46.04英寸×32.42英寸。其中46.04=3315÷72,32.42=2334÷72。
对于喜欢较真的人来说,ACDSEE的这种偷懒造成了更深层次的失真:用例1中的第二幅图像是一张扫描形成的TIFF图像,在TIFF文件结构中记载了扫描时扫描仪使用的DPI值——200 DPI。在ACDSEE 8中打开此图像文件,点击“文件->属性”菜单,在显示出来的文件属性中即可看到扫描DPI,及按照扫描DPI换算,这张图片对应原始纸质页面的大小——16.57英寸×11.67英寸。这个尺寸与46.04英寸×32.42英寸相比,实在是差得太远了一点。
而如果用verypdf的Image2Pdf v1.7对同一张图片进行转换,可以看出转换后的PDF页面大小为16.57英寸×11.67英寸,即在PDF Reader中选择按照“实际大小”进行显示,显示出来的图像大小,正好与原始纸质文件的大小一模一样。显然这样的结果更符合文档电子化的要求和习惯。
Image2Pdf的这种“保真”转换过程可以描述如下:
在了解了相关预备知识后,再回顾前面提到的图像转PDF需要面对的问题,其答案自然明了:
总之,对于象我这样有特殊要求的人来说,在目前的情况下要想得到满意的结果,还是只能贯彻“人要靠自己”的原则。当然也没有必要重新发明轮子,在我看来最理想的情况就是能够在现有开源项目基础上,通过必要的修改和补充,就能达到我的要求。但是google的结果令我稍微有点惊讶:虽然目前最权威的图像codec开源项目都是基于C的,包括JPEG LIB、libpng、libtiff等,但是偏偏在PDF生成领域,JAVA似乎比C多,包括iText等一大批开源项目,而C只有PDFlib、ClibPDF、Panda等有数的几个。
ClibPDF从参考手册上看,在绘图等功能方面很有特色,但是对于图像文件的支持较差,而且要付费,所以我粗看了一下,没有深究。
Panda的功能、接口都非常简洁明了,生成的PDF文件也没多少费话,所以我花时间详细试了一下。结果发现一个小小的小缺点:它的内存漏洞实在是太多 了点,补都补不过来,最后只好放弃。
相比之下,PDFlib堪称内容丰富、功能强大,某些高级功能(web优化、权限控制等)虽然要付费才能看到,但就算是免费开源出来的PDFLib Lite,对于各种图像格式的支持也足够一般性使用了,而且基本上没什么明显的内存漏洞。因此我在DACapturer中试用了一把。但是在使用一段时间后就发现一些问题:
由于问题的根子出在TIFF文件上,所以我的目光很快集中到llibtiff源代码中包含的tiff2pdf.c。这份代码是我见过最简洁的PDF生成代码,而且由于是libtiff自己提供的,马马虎虎算是出身名门、血统纯正,对TIFF文件的支持当然很可观,我就是用它弥补了PDFLib不支持JPEG/OJPEG压缩TIFF文件的问题。当然这份代码也不是一点问题没有:
好在这份代码比较简单,结构中规中矩,改起来不是太难。最终我以它为基础实现了新版图像转PDF内核,并结合大名鼎鼎的CxImage,将对图像格式的支持从TIFF扩展到了JPG、PNG、BMP和GIF,成为公开发行的免费软件FreePic2Pdf,能够实现:
原始图像 | PDF中的图像数据 | ||||||
序号 | 说明 | 宽×长 (象素) |
解码器 | 文件长度 (字节) |
解码器 | BitsPerComponent /ColorSpace |
数据流 长度 (字节) |
01 | 黑白TIFF | 1728×1103 | CCITT G3 | 50,401 | CCITT G4 | 1/DeviceGray | 41,638 |
02 | 黑白TIFF | 3315×2334 | CCITT G4 | 35,518 | CCITT G4 | 1/DeviceGray | 34,981 |
03 | 彩色JPEG格式TIFF | 512×384 | DCTDecode | 24,428 | DCTDecode | 8/DeviceRGB | 23,169 |
04 | 灰度JPG | 445×600 | DCTDecode | 34,167 | DCTDecode | 8/DeviceGray | 34,167 |
05 | 彩色JPG | 1024×768 | DCTDecode | 102,776 | DCTDecode | 8/DeviceRGB | 102,776 |
06 | 16级灰度GIF | 800×1199 | LZWDecode | 124,738 | FlateDecode | 4/Indexed/DeviceRGB | 126,407 |
07 | 256色GIF | 130×129 | LZWDecode | 8,408 | FlateDecode | 8/Indexed/DeviceRGB | 7,031 |
08 | 黑白PNG | 32×32 | FlateDecode | 164 | CCITT G4 | 1/DeviceGray | 40 |
09 | 2色彩色PNG | 32×32 | FlateDecode | 112 | FlateDecode | 1/Indexed/DeviceRGB | 17 |
10 | 256级灰度PNG | 600×905 | FlateDecode | 289,059 | FlateDecode | 8/DeviceGray | 278,021 |
11 | 16级灰度PNG | 720×1053 | FlateDecode | 74,322 | FlateDecode | 4/Indexed/DeviceRGB | 73,199 |
12 | 24位色PNG | 350×560 | FlateDecode | 72,107 | FlateDecode/PNG | 8/DeviceRGB | 71,954 |
13 | 15位色BMP | 260×235 | 未压缩 | 122,266 | FlateDecode/PNG | 8/DeviceRGB | 31,764 |
14 | 16色BMP | 940×20 | RLE | 8,134 | FlateDecode | 4/Indexed/DeviceRGB | 2,832 |
图像文件总长度(字节) | 946,600 | PDF文件总长度(字节) | 838,932 |
对比表3.1和表1.3,可以看出FreePic2Pdf优先考虑图像质量,其次考虑压缩比、生成速度。
另外用例1的第一张图片很有趣,用libtiff带的TiffInfo查看它的信息如下:
TIFF Directory at offset 0xc3c6
Image Width: 1728 Image Length: 1103
Resolution: 204, 98 pixels/inch
Bits/Sample: 1
Compression Scheme: CCITT Group 3
Photometric Interpretation: min-is-white
FillOrder: lsb-to-msb
Orientation: row 0 top, col 0 lhs
Samples/Pixel: 1
Rows/Strip: (infinite)
Planar Configuration: single image plane
Page Number: 1-1
Software: fax2tiff
Group 3 Options: (0 = 0x0)
Fax Data: clean (0 = 0x0)
Bad Fax Lines: 0
Consecutive Bad Fax Lines: 0
这张图片在宽度方向上的扫描DPI约为长度方向的两倍(204/98),如果对这种差异处理不好,会带来意外的结果。以ACDSEE为例,5.0.1版显示该图片时就会变形,页面顶部的圆变成了扁椭圆,到8.0版时显示出了正圆,但是图像的长度从1103变成了2206,而且在ACDSEE 8打印和用PDF创建插件转换成PDF后,在PDF文件的图像物理表示中,这张图片的长度均描述为2206象素。显然,ACDSEE内部对图像数据流进行了更改(沿长度方向放大一倍),以符合原长宽比,这对于图像显示软件来说无可厚非,但是对于PDF转换软件来说就有点多余,会增加最终PDF的文件长度。Image2Pdf没有对这张图片的物理表示进行更改,而是试图通过调整图片的逻辑表示,由PDF Reader在显示时进行长宽比调整。但不幸的是,Image2Pdf v1.7似乎把比例算反了,结果导致最终PDF显示出来后,圆变成了长椭圆。FreePic2Pdf吸取了这些教训,能够通过对图像逻辑表示的正确设置,在不改变物理表示的情况下, 以正确的长宽比例显示该图像。
为了验证我提出的上述问题及其解决方法,我开发了一个免费的图像转PDF工具FreePic2Pdf,有需要的可以到我的网站下载。该软件考虑的优先顺序依次是:图像质量、PDF文件大小、转换速度。
前面说了半天图像转PDF,自然会产生一个问题:将PDF转成图像又如何?
我个人认为目前将PDF转成图像也可以分成两种:
第一种的代表软件包括verypdf公司的PDF2HTML等。PDF2HTML除了将页面转成图像,还能生成包含图像和翻页按钮的HTML页面,方便在没有安装PDF Reader的机器上浏览原PDF文件的内容。不过在这种“眉毛胡子一把抓”的转换结果里要取出某幅图像的内容,大概只能用Photoshop慢慢抠了。
第二种的代表软件包括Adobe Acrobat Professional(菜单项:Advanced->Export All Images)。如果喜欢开源代码,也可以看看Xpdf组织提供的pdfimages。从我使用的结果看,Acrobat略显霸道,不管原来的图像是什么格式,转换出来都成了一种格式。pdfimages稍好一点,JPG数据流 可以直接导出成JPG文件,其它无损数据流解码后导出为ppm文件,不过对于某些特殊色彩空间(ColorSpace)的JPG数据流,直接导出会导致偏色,只能解码后导出为ppm文件。 其实部分特殊色彩空间可以导出为JPG压缩的TIFF文件,从而避免对数据进行解码、再压缩,pdfimages不知道为什么没有考虑。
以IT界的眼光来看,电子文档发展到现在历史也不算短了,而且由于巨大市场前景的诱惑,各厂家也都纷纷推出了自己的格式。单纯从以支持扫描图像为主的电子文档来说,格式虽多,但是能够成气候、形成标准的,除了PDF格式外,还有多页TIFF、JBIG2、DjVu等。这些格式的共同点是:
当然这些格式目前的影响力都不如PDF,我认为原因也都差不多:
这个应该算比较老的标准了,由于扫描、出版界传统上就习惯用TIFF格式,所以将多页TIFF作为电子文档的一种标准格式,应该是顺理成章的事,国内部分省市先行制定的电子档案管理相关规定也曾要求用多页TIFF作为扫描电子文件的存储格式。
但是从实际情况看,真正用多页TIFF存储的电子文档并不多,在2005年颁布执行的《中华人民共和国行业标准DA/T31—2005 纸质档案数字化技术规范》中,干脆就没多页TIFF什么事:
8图像存储
8·1存储格式
8·1·1采用黑白二值模式扫描的图像文件,一般采用TIFF(G4)格式存储。采用灰度模式和彩色模式扫描的文件,一般采用JPEG格式存储。存储时的压缩率的选择,应以保证扫描的图像清晰可读的前提下,尽量减小存储容量为准则。
8·1·2提供网络查询的扫描图像,也可存储为CEB、PDF或其他格式。
多页TIFF为何会遭到冷落呢?我猜测的原因包括:
但是对于TIFF格式的生命力,我个人从未表示怀疑:与某些静态图像格式不同,TIFF标准一直在与时俱进,不断将先进的图像压缩技术吸收进来,目前已经支持主流的CCITT、JPEG、LZW、ZIP等技术,新版本的草案中则计划包含对JPEG 2000、JBIG2等先进算法的支持。这些都让我充满期待。
这种格式专门针对以文字为主、黑白扫描的图像文件,属无损压缩,据称比G4压缩算法的压缩率高很多,目前已成为ISO标准,PDF从1.4版(Acrobat 5.0)开始允许内嵌JBIG2图像,未来的TIFF标准也打算吸收JBIG2压缩算法。
JBIG2的原理类似OCR:先对图像进行分割、匹配,在识别出子图像(如文字)后,将整幅图像看作子图像及其位置的集合,存储时只存储子图像和子图像出现的位置,其它背景信息全部过滤掉,因此不仅能够提供很高的压缩比,而且能够实现类似文字检索的图像全文检索。
虽然前景诱人,但是我个人认为JBIG2目前还存在下列问题:
这个也是针对扫描电子文档的,但是与JBIG2不同,针对的是彩色、图文混排的图像。
DjVu的原理是先对图像进行分析,然后按照内容分层,包括背景层、文字层、图像层等,对不同的层使用不同的压缩算法和参数,以获得最好的图像质量和压缩比。
与JBIG2不同,DjVu不仅有djvuzone组织在维护,而且有开源项目DjVuLibre作为支撑,因此现在不仅有不同平台下的编码、解码器,连查看DjVu文件的IE插件都发布了,未来应该大有希望。
双层PDF是这样的PDF文件:PDF文件的每一页都包含两层,下层是从纸质文件扫描出来的原始图像 ,上层是用OCR软件对扫描图像进行识别后产生的文字结果,但字体效果设置成透明。这样用户在阅读PDF文件时看到的是扫描图像,可以100%保留原始版面效果(包括公章、签名),在需要的时候,又可以通过 透明的文字信息支持选择、复制、检索等功能。
与普通PDF文件相比,双层PDF能够同时兼顾视觉效果和使用方便性,因此在国内办公、档案领域正在引起重视,我个人相信会有美好的“钱途”。
显然,双层PDF的内容检索、内容复制与OCR识别结果有直接的关系。先不说目前国内OCR软件的识别率如何,最关键的一点是目前没有任何一个中文OCR引擎是免费、开源的(英文的则有gocr等一批),所以双层PDF生成工具也都不是免费的,而是“面向企业市场”,我相信穷困的个人用户在不违法的情况下很难消受得起。