最近研究怎么在 PDF 里实现 JBIG2 压缩算法,这是目前对黑白二值图像压缩率最高的算法,然后我发现这个压缩算法的实现有巨大问题,这个算法的实现需要先提取图像中的字符,但是压缩的时候,判断两个字符是否相似居然是依赖像素的数量,这样会导致质量差的扫描本出现大量字形相似的文本字符丢失的情况。(国外社区有很多类似讨论,中文字符比较复杂不确定会不会出现类似情况,但还是建议 PDF 使用 JPG 或者 CCITT G4 压缩。
Technical Support
Apryse SDK
Q: We have run into an issue with a specific file when it is compressed with PDFNet using JBIG compression. With this file, it is changing a character from н to и . Below is a screenshot to show the difference, as it is not obvious when just...
Update:
搜索 DjVu 发现更多中文字符出错的例子,和 PDF 是相同的问题。
图一「惜卷详刻书时代」
图二「于刊梓源流,盖卷尽晰」
卷是错字,实际原版是未字:(来源@屠龙少年周旭)
3 个赞
amob
2025 年9 月 23 日 00:16
2
老马早就讲过,不少都是十多年前文章。学习图像格式和处理,还是得先看他,国内第一人。
BTW:PDF的JBig2压缩与DjVu的JB2压缩是一路货色,在采用有损压缩时同样存在把某些内容“有损”掉的可能,这就是为什么我说我在有选择的情况下,从来不要DjVu或从DjVu转出来的PDF(不论是否采用JBig2压缩),或者直接采用JBig2压缩的PDF的
DjVu在压缩文字部分时通常采用JB2压缩,可以是无损,也可以是有损。在有损情况下,如果扫描分辨率不足,可能会因为误码而导致生成的DjVu出现错别字,因此在我见过的DjVu相关技术文档中,都强调扫描分辨率不要低于300 DPI。误码的原因、实例见《DjVu转PDF》一文。
从目前的情况看,汉字的误码率要高于字母文字。
在JB2有损压缩时,一般要在开始搜索符号(字符)前,先对版面进行去斑(clean),即将细小的孤立点当作噪声点去除。具体多大的点算“细小”,则由DPI决定。djvulibre中cjb2.cpp的相关计算代码为:
dpi = MAX(200, MIN(900, dpi));
largesize = MIN( 500, MAX(64, dpi));
smallsize = MAX(2, dpi/150);
tinysize = MAX(0, dpi*dpi/20000 - 1);
即在计算时,先对用户指定的DPI值有效性进行检查,小于200 DPI的一律算200 DPI,大于900 DPI的则算900 DPI;largesize是符号最大尺寸,长、宽大于等于此值的连通域均会被拆分,以避免符号粘连;smallsize是符号最小尺寸,长、宽小于等于此值的连通域均 将视需要合并,以避免一个字母被拆成两半(如字母i上面的点和下面的竖线通常是不连通的);tinysize是噪声点尺寸,长、宽小于等于此值的孤立连通域 可能会被当作噪声点加以清除。
简单来说,对于同一个原始图像,如果DPI小于等于200,只有长、宽为1个象素的孤立点会被clean掉;在DPI为300时,长、宽小于等于3个象素的孤立区域会被clean掉。
如果JB2选项选的是“去斑(clean)”,通常在完成上述去斑过程后,即按无损压缩处理;如果选择的是“有损(lossy)”,则在去斑后,再进行符号匹配,并对“相同”(其实是“相似”)的符号进行合并。至于什么样的符号算“相同”,则与DPI、有损级别(losslevel)有关:DPI和losslevel值越大,允许两个“相同”符号之间的差异越大,即越容易将两个有差异的符号判别为“相同”。在djvulibre中,losslevel的合法值是0~200:0即“无损”,1即“去斑”,通常“有损”时losslevel=100。
djvulibre的符号匹配算法是外国人写的,对字母、数字来说,有损JB2压缩能在较小的风险代价下,获得较高压缩比。但是对中文来说,故事就没这么美好:很多字本来就很像(如“己”和“已”、“人”和“入”、“面”和“而”等),扫瞄质量如果差点(笔画缺胳膊少腿),再被clean过程去掉点孤立的笔画或点,在有损压缩时就 可能将相似字判别成相同字。在读书园地BBS上已经有人贴过这样的实例:采用CCITT无损压缩的02H的PDG文件上没有错别字,但是同一个文件的05H版(DjVu)就出现错别字(将“面”和“而”混了)。
快速版由于文件大小比清晰版小得多,其清晰度虽然比清晰版差,但通常情况下也不至于因此而造成太大的阅读障碍,因此在某段时期内在园地广为流行,甚至有人声称“宁要快速版,不要清晰版”。但是好景不长,在快速版的真面目被进一步揭开以后,很快就成了“过街老鼠”,如今在园地再无老鸟敢要快速版,以前收藏的快速版PDG也都成了鸡肋:为了追求较高的压缩比,快速版PDG全部采用有损DjVu压缩,而快速版本身的清晰度就不是太好,在DjVu有损压缩时,可能会将笔画残缺的相似字识别为同一个字,造成错别字。相比之下,清晰版全部采用无损CCITT G4压缩,完全忠实于原著。有人曾在园地贴出过实际的PDG文件并进行对比:同一页的清晰版没有错别字,而快速版就出现错别字。
前面费了那么多口水,还是总结一下,对图像格式的选择给点建议吧:
对于白底黑字的扫描图像,建议灰度扫描(除非您有非常专业的扫描仪),扫描分辨率不低于300 DPI,有条件的话再放大处理成600 DPI,然后减色成单色,存为CCITT G4压缩的TIFF文件,或无损压缩的DjVu文件。
如果想玩动画,在常见图像格式中只能选GIF。
如果想玩透明,在常见图像格式中只能选GIF、PNG,不过GIF只支持基于调色板的背景色透明,PNG还支持Alpha通道透明。 对基于调色板的GIF、PNG,透明与否不会改变文件长度,增加Alpha通道则会增加PNG文件的长度。
如果是图像处理的中间格式,建议选择BMP或PNG。
如果图像中有大片纯色,建议选择GIF或PNG,同时进行减色处理。
如果是连续色调图像,如自然风光、人物等照片,或彩色、灰度扫描图像,建议选择JPEG。
如果想定量控制生成的文件大小,可以考虑JPEG 2000。
对于JPEG格式,建议不要选择CMYK色彩空间。
对于TIFF格式,建议不要选择除CCITT G3/G4、LZW之外的压缩算法。
对于无损压缩的GIF、PNG、采用CCITT G3/G4或LZW压缩算法的TIFF等,在图像的像素尺寸不变情况下:
画面越“干净”,最终文件长度越小。
“减色”也能有效减小最终文件长度,如从24位彩色减成256级灰度,或从256级灰度减成16级灰度。
1 个赞
amob
2025 年9 月 23 日 00:29
3
last_idol:
CCITT G4
纯黑白(最多人接触的扫描图像来自读秀,都是16级灰度或者256级灰度)和干净的图像还是偏少的,这么推荐太草率了。在极限情况CCTI G4压缩后反而体积增大。一般人知道JPEG压缩和zip压缩就可以了,覆盖最常用的格式jpg和png,这两种最常用最不容易出问题。tiff(CCITT G4压缩)有兼容性问题,少用。
说到底,在这个存储白菜价的时代,不要牺牲图像质量弄高压缩率的有损压缩了,原始未压缩档案找不到了反而难受。
CCITT G4是一种无损压缩算法,只能用于压缩黑白二值图像,不能用于灰度或彩色图像。该算法最早用于传真领域,现在则扩展到出版等领域。传真领域通常传递的都是“白纸黑字”,所以对于以白底为主,中间有黑色文字、线条的图像,CCITT G4有很好的压缩比,但如果超出这个范围,则可能会越压越大。我就听一个朋友说过,某人开发传真软件,结果一次测试的时候软件突然崩溃,打电话过去一问,原来对方把一条毛巾放进传真机里传了过来。coolman在测试山寨版PDG编码器时,也曾把一张人物 + 风光的彩色照片抖动处理成半调黑白图像(用黑点的疏密程度表示灰度),结果发现压缩成CCITT G4的PDG后比原始的BMP文件要长得多。
总之一句话:CCITT G4作为一种无损图像压缩算法,画面越干净,压出来的文件长度越小。
TIFF标准比较开放,自定义空间比较大,所以TIFF根本就是一个大空筐,各家都在不停地往里面塞自己的东西,在某些情况下会出现兼容性问题。可能就是因为这个原因,虽然TIFF文件出现得比较早,但从NetScape到IE到Opera到Chrome,没有一款HTML浏览器支持TIFF。
1 个赞
早在20多年前,在超星自己的读书社区论坛上,就有人提出了快速PDG(150dpi)原书不误,而所谓的扫描图像反而是错别字的“咄咄怪事”,它就是有损压缩算法造成的。以为图像版图书就是“全真”,那是过于naive了。
1 个赞
有损压缩是知道的,但图像里字形相似的不同字符会被替换成同一个字符,真是第一次见识。
以前专门看过他的博客,有点印象但当时没意识到问题会这么严重,我以为只是少笔画。
如果选择的是“有损(lossy)”,则在去斑后,再进行符号匹配,并对“相同”(其实是“相似”)的符号进行合并。至于什么样的符号算“相同”,则与DPI、有损级别(losslevel)有关:DPI和losslevel值越大,允许两个“相同”符号之间的差异越大,即越容易将两个有差异的符号判别为“相同”。
相同符号合并,在文本字符压缩领域应该算是首要方法和技巧了,但用在图像上,相当于搞了一次OCR然后判别为字符级(bit级)的相等,这在原理上是错误或者有严重漏洞的,特别在分辨率低的情况下。
2 个赞
感觉现在图片格式用png就够了,现在存储容量很大,没必要省空间,png新标准既支持动画又支持exif和hdr,有损压缩除了jpg还有webp,其他格式存储的话都没必要了。
amob
2025 年9 月 23 日 03:04
11
webp也是基本完美的格式,压缩率最高,支持大部分特性,奈何推广率太低了,只在网页上有广泛使用。
DjVu格式是获得图灵奖的如今ai领域的牛人 le cun 搞的,他是法国人,所以起了这么个奇怪的名字。他研究ai的起点就是为了解决OCR问题,所以据称 DjVu 图像文件OCR时的速度极快(我自己没测试过),根本原因可能在于DjVu内部存储的图像块(字块)本身就是合并过的,它实际不需要一个个字符识别,只需要识别分类图像然后批量替换就行了。这种设计有它的高明之处,但如果图像分辨率低,压缩很厉害,就会导致相近字符错误。
1 个赞
amob:
webp
推广慢主要苹果不支持,被骂了很多年前几年才不情不愿的引入了原生支持,据说是因为在苹果的低端设备上解码会出现卡顿的问题,要先等那些设备淘汰了。(但是又出现了新王者,AVIF 和 JPEG XL
2 个赞
我也来分享一下扫描心得。
对于白底黑字的扫描图像,
尤其是字小笔画多的中文,
我是直上 600 dpi,
Scan type 选 Gray (Error Diffusion)。
我是用 Fuji Xerox DocuPrint M225 dw 扫的。
不确定其它家的有没有 Gray (Error Diffusion) 可以选。
或是同样是 Error Diffusion, 效果会不会和 Fuji Xerox 一样。
Error Diffusion 大家可能比较陌生,
简单讲就是用黑白点去抖色仿真灰阶,
因为基本上还是黑白两色,
所以文件体积还可以接受。
最后再用 ScanTaior 最后一步去杂点,
就可以得到效果不错体积又小的黑白图。
我不确定去杂点会不会影响到字体,
只要笔画的点大于一个 pixel 应该是安全的。
DPI 这么高的扫描本去杂点没什么影响。最好网盘再存一份原始的扫描档(保险。
清晰度我觉得 OK,
不过现在机器老了有点状况,
页面会出现一条灰带。
可能是那边LED灯亮度衰减,
或是传感器老化吧。
还有这台是低阶机种,
扫 600 dpi 速度比较慢。
Xerox 作为複印机开山祖师,
在这方面还是有点功力的。
1 个赞