e-works数字化企业网  »  文章频道  »  基础信息化  »  移动应用

Android 中图片压缩分析(上)

2017/11/14    来源:腾读去    作者:佚名      
关键字:Android   压缩分析  
在 Android 中进行图片压缩是非常常见的开发场景,主要的压缩方法有两种:其一是质量压缩,其二是下采样压缩。
    Android 在之前从某种程度来说使用的算是 libjpeg 的功能阉割版,压缩图片默认使用的是 standard huffman,而不是 optimized huffman,也就是说使用的是默认的哈夫曼表,并没有根据实际图片去计算相对应的哈夫曼表,Google 在初期考虑到手机的性能瓶颈,计算图片权重这个阶段非常占用 CPU 资源的同时也非常耗时,因为此时需要计算图片所有像素 argb 的权重,这也是 Android 的图片压缩率对比 iOS 来说差了一些的原因之一。
 
    四、图像压缩与 Huffman 算法
 
    这里简单介绍一下哈夫曼算法,哈夫曼算法是在多媒体处理里常用的算法之一。比如一个文件中可能会出现五个值 a,b,c,d,e,它们用二进制表达是:
 
    a. 1010
 
    b. 1011
 
    c. 1100
 
    d. 1101
 
    e. 1110
 
    我们可以看到,最前面的一位数字是 1,其实是浪费掉了,在定长算法下最优的表达式为:
 
    a. 010
 
    b. 011
 
    c. 100
 
    d. 101
 
    e. 110
 
    这样我们就能做到节省一位的损耗,那哈夫曼算法比起定长算法改进的地方在哪里呢?在哈夫曼算法中我们可以给信息赋予权重,即为信息加权,假设 a 占据了 60%,b 占据了 20%, c 占据了 20%,d,e 都是 0%:
 
    a:010 (60%)
 
    b:011 (20%)
 
    c:100 (20%)
 
    d:101 (0%)
 
    e:110 (0%)
 
    在这种情况下,我们可以使用哈夫曼树算法再次优化为:
 
    a:1
 
    b:01
 
    c:00
 
    所以思路当然就是出现频率高的字母使用短码,对出现频率低的使用长码,不出现的直接就去掉,最后 abcde 的哈夫曼编码就对应:1 01 00
 
    通过权重对应生成的的哈夫曼表为:
 
Android 中图片压缩分析(上)
  
    定长编码下的abcde:010 011 100 101 110,使用哈夫曼树加权后的编码则为 1 01 00,这就是哈夫曼算法的整体思路(关于算法的详细介绍可以去查阅相关资料)。
 
    所以这个算法一个很重要的思路是必须知道每一个元素出现的权重,如果我们能够知道每一个元素的权重,那么就能够根据权重动态生成一个最优的哈夫曼表。
 
    但是怎么去获取每一个元素,对于图片就是每一个像素中 argb 的权重呢,只能去循环整个图片的像素信息,这无疑是非常消耗性能的,所以早期 android 就使用了默认的哈夫曼表进行图片压缩。
 
    五、libjpeg 与 optimize_coding
 
    libjpeg 在压缩图像时,有一个参数叫 optimize_coding,关于这个参数,libjpeg.doc 有如下解释:
 
Android 中图片压缩分析(上)
 
    由上可知,如果设置 optimize_coding 为 TRUE,将会使得压缩图像过程中,会先基于图像数据计算哈弗曼表。由于这个计算会显著消耗空间和时间,默认值被设置为 FALSE。
 
    那么 optimize_coding 参数的影响究竟会有多大呢?查阅一些博客资料介绍,使用相同的原始图片,分别设置 optimize_coding=TRUE 和 FALSE 进行压缩,发现 FALSE 时的图片大小大约是 TRUE 时的 5-10 倍。换言之就是相同文件体积的图片,不使用哈夫曼编码图片质量会比使用哈夫曼低 5-10 倍。
 
    关于这个差异我们再去查阅其他资料,发现有两篇讨论非常热烈:Investigate using “optimize_coding” when encoding to JPEG,About libjpeg optimize_coding,甚至Skia 的官方人员也参与了讨论,他据此测试了两组数据:
 
Android 中图片压缩分析(上)
 
    可以看到效果并不是 5-10 倍的体积差距,最多也就在 2 倍而已,有国人也测试了一下,结果一致:JPEG Optimized Huffman。
 
    尽管如此,社区里对此的疑虑并没有彻底打消,最终,官方人员修改了这个默认的实现:skia / skia.git / 0a35620a16b368356888d15771392fb00cbb777d(https://skia.googlesource.com/skia.git/+/0a35620a16b368356888d15771392fb00cbb777d ) 。在 SkImageDecoder_libjpeg.cpp 文件中给 optimize_code 赋值了一个默认值 TRUE。
 
    六、Android 与 optimize_coding
 
    那么在 Android 中有没有使用哈夫曼变长编码呢?查阅了 7.0 源码,如下:
 
Android 中图片压缩分析(上)
 
    可以看到注释里面很清楚,默认是哈夫曼变长编码,而不是算数编码。同时去查阅 14 年时的 Android 4.4 源码,发现依旧如此。
 
    对于optimize_coding,早期的 Android 考虑到性能瓶颈,将其设置为 FALSE。但是,现在 Android 手机性能比以前好很多,所以目前性能往往不是瓶颈,时间和压缩质量反而成为更重要的指标了。为此,Google 在 Android 7.0 版本左右,也做了相应修改,如 7.0 和 6.0 源码所示:
 
Android 中图片压缩分析(上)
 
    七、Android JPEG VS. iOS JPEG
 
    经过上面的介绍大家应该了解了为什么 Android 的 JPEG 图片压缩率会比 iOS 小一些,那么还有另一个问题就是为什么同一张 PNG 图片设置成同样的压缩质量压缩成 JPEG 之后,Android 输出的图像质量会比 iOS 差一些呢,经过相关资料的查找,发现造成这个结果有两方面的因素。
 
    第一个因素是 JPEG 编码过程中有一个步骤是颜色空间 RGB -> YUV 的转换,之前的 Android 版本同样考虑到性能问题,skia 引擎写了一个函数替代了原来 libjpeg 的转换函数,好处是提高了编码速度,坏处就是牺牲了每一个像素的精度。
 
    第二个因素是离散余弦变换有三种方式,Skia 引擎选择了 JDCT_IFAST,JDCT_IFAST 是最快的变换方式,当然也是精度最差的一种。
  
    上面两种因素第一个会造成色调偏差,第二个会造成色块的出现,所以如果需要提高压缩之后的图像质量,可以考虑从这两方面入手。
 
    八、总结
 
    首先,从 Android 7.0 版本开始,optimize_code 标示已经设置为了 TRUE,也就是默认使用图像生成哈夫曼表,而不是使用默认哈夫曼表。而至于这个标志所产生的体积差距也没有 5-10 倍那么大,大约可以在原图的基础上缩小 10%~50% 的体积,经过修改前后不同 Android 版本实测,数据吻合。
 
    其次,如何提高 Android 的压缩率,这里需要提到两个库,一个是 mozilla/mozjpeg,另一个是 libjpeg-turbo,前者是一个来自 Mozilla 实验室的 JPEG 图像编码器项目,目标是在不降低图像质量且兼容主流的解码器的情况下,提供产品级的 JPEG 格式编码器来提高压缩率以减小 JPEG 文件的大小,后者相当于是一个 libjpeg 的增强版,前者也是基于后者,在后者的基础上进行了一些优化。
 
    所以想要提升图片压缩率的可以从这两个库着手,网上资料也不少,后续有机会可以测试一下这两个库,然后给大家分享一下。
  
    最后,编码方式除了哈夫曼之外,还有定长的算术编码,这个算法的详细介绍大家可以网上查阅一下。对比哈夫曼编码和算术编码,网上相关资料显示算术编码在压缩 jpeg 方面可以比哈夫曼编码体积小 5%~12%,所以需要提升图片压缩率的同样也可以尝试从切换成算术编码这方面入手。
 
    九、参考
 
    为什么Android的图片质量会比iPhone的差?(http://blog.sina.com.cn/s/blog_12ce70a430102v1p3.html )
 
    JPEG arithmetic coding(http://www.rw-designer.com/entry/1311 )
 
    Comparison Arithmetic Coding versus Huffman(http://www.binaryessence.com/dct/en000134.htm )
 
    Investigate using "optimize_coding" when encoding to JPEG(https://bugs.chromium.org/p/skia/issues/detail?id=3460 )
 
    About libjpeg optimize_coding(https://groups.google.com/forum/#!topic/skia-discuss/p0IcyBoU8P0
 
责任编辑:李欢
本文为授权转载文章,任何人未经原授权方同意,不得复制、转载、摘编等任何方式进行使用,e-works不承担由此而产生的任何法律责任! 如有异议请及时告之,以便进行及时处理。联系方式:editor@e-works.net.cn tel:027-87592219/20/21。

分页导航:

兴趣阅读
相关资料
e-works
官方微信
掌上
信息化
编辑推荐

基于腾讯微校平台的校园移动办公APP设计与实现

新闻推荐

伟创力斩获“2021中国汽车及零部件行业发展创新技术奖”

博客推荐

关于创新的联想和联想的创新

视频推荐