常常看到有人问:“安卓版微信发出去的图片怎么那么渣!比iPhone的差远了!”。不仅是微信,不少应用安卓版的图片质量就是要比iPhone版逊色不少,这究竟是怎么回事? 咱们团队最初也纠结过这个问题,费了半天劲、绕了好大圈,直到最后才发现,原来这是谷歌犯得一个“小”错误,并且一直错到了今天。 谷歌的错就在于:libjpeg。 libjpeg是普遍使用的开源JPEG图像库(参考 http://en.wikipedia.org/wiki/Libjpeg ),安卓也依赖libjpeg来压缩图片。经过查看源码,咱们会发现安卓并非直接封装的libjpeg,而是基于了另外一个叫Skia的开源项目 (http://en.wikipedia.org/wiki/Skia_Graphics_Engine)来做为的图像处理引擎。Skia是谷歌本身维 护着的一个大而全的引擎,各类图像处理功能均在其中予以实现,而且普遍的应用于谷歌本身和其它公司的产品中(如:Chrome、Firefox、 Android等)。Skia对libjpeg进行了良好的封装,基于这个引擎能够很方便为操做系统、浏览器等开发图像处理功能。 libjpeg在压缩图像时,有一个参数叫optimize_coding,关于这个参数,libjpeg.doc有以下解释: boolean optimize_coding TRUE causes the compressor to compute optimal Huffman coding tables for the image. This requires an extra pass over the data and therefore costs a good deal of space and time. The default is FALSE, which tells the compressor to use the supplied or default Huffman tables. In most cases optimal tables save only a few percent of file size compared to the default tables. Note that when this is TRUE, you need not supply Huffman tables at all, and any you do supply will be overwritten. 这段话大概的意思就是若是设置optimize_coding为TRUE,将会使得压缩图像过程当中基于图像数据计算哈弗曼表(关于图片压缩中的哈弗曼表,请自行查阅相关资料),因为这个计算会显著消耗空间和时间,默认值被设置为FALSE。 这段解释乍看起来没有任何问题,libjpeg的代码也经受了十多年的考验,健壮而高效。但不少人忽略了这一点,那就是,这段解释是十多年前写的,对于当 时的计算设备来讲,空间和时间的消耗多是显著的,但到今天,这彷佛不该再是问题,相反,咱们应该更多的考虑图片的品质(愈来愈好的显示技术)和图片的大 小(愈来愈依赖于云服务)。 谷歌的Skia项目工程师们最终没有设置这个参数,optimize_coding在Skia中默认的等于了FALSE,这就意味着更差的图片质量和更大的图片文件,而压缩图片过程当中所耗费的时间和空间其实反而是能够忽略不计的。那么,这个参数的影响究竟会有多大呢? 经咱们实测,使用相同的原始图片,分别设置optimize_coding=TRUE和FALSE进行压缩,想达到接近的图片质量(用Photoshop 放大到像素级逐块对比),FALSE时的图片大小大约是TRUE时的5-10倍。换句话说,若是咱们想在FALSE和TRUE时压缩成相同大小的JPEG 图片,FALSE的品质将大大逊色于TRUE的(虽然品质很难量化,但咱们不妨说成是差5-10倍)。 咱们又对Android和iOS进行了对比(均使用标准的JPEG压缩方法),两个系统都没有提供设置optimize_coding的接口(经过阅读源 码,咱们已经知道Android是FALSE,iOS不详),当压缩相同的原始图片时,结果也是同样,iOS完胜。想要品质接近,文件大小就会差出 5-10倍,而若是要压缩出相同大小的文件,Android的压缩品质简直就是惨不忍睹。 结果说明,苹果很清楚optimize_coding参数和哈弗曼表的意义,这里须要特别指出,苹果使用的哈弗曼表算法与libjpeg(及咱们后来自行 采用的libjpeg-turbo)不一样,像素级能够看出区别,苹果彷佛基于libjpeg又进行了进一步的优化,压缩出来的图片细节上更柔和、更平滑。 以上试验,咱们尝试过多个原图、多种压缩比例,试验结果均相似,若有兴趣,您不妨也自行进行尝试。