Total Pageviews

Saturday, 6 October 2018

图片优化实践

这里说的图片优化,目标是想尽可能降低图片大小,但又要保证质量不错,非常矛盾。不过降低图片大小,可以剩一大笔流量钱,降低负载,还能提升用户体验,值得花点功夫。
前端方面有一些关于图片加载速度的优化,例如CSS 画图,CSS 合并素材,甚至用CSS 把图片Base64 编码(不推荐),和这份笔记关系不大。

格式选择

不同的需求选择不同的格式, JPEG 能够满足的需求没必要选择PNG。
图片来源:《web前端图片极限优化策略》,原图是Google的Image Optimization

WebP、SharpP

目前对于WebP的支持已经很好了,所以新业务能够选择WebP,就选WebP。
豆瓣的相册切到了WebP,另外提供了一个让图片变清晰的思路:把图片尺寸拉大到2倍,然后缩小成1倍。
图片清晰度大大提升,还降低了图片大小:2x WebP(73k) < 1x JPG(119k),效果如下图(图片来源豆瓣波希米亚的日记)。
不过采用WebP 之后,用户“另存为”不太方便,毕竟大家对PNG和JPEG 比较熟悉。
豆瓣的WebP 实践:
有趣的是,WebP基于VP8,VP8的下一代是VP9,VP9的对手是HEVC/H.265BGP基于HEVC,据说表现比WebP好很多,不知为啥应用不多,因为专利?
腾讯基于HEVC 搞出了一个SharpP 格式,听说秒天秒地,目前已在腾讯云CDN 上应用,不过接入的大都是腾讯自家的产品:
看起来确实不错,听说在移动端解码速度也很快,不过如此大规模使用估计花了不少专利费。第三方用户使用也不方便,得使用X5内核,且只能用腾讯云的CDN,这样被活活绑死的事情,愿意的人应该不多。另外腾讯还搞了一个TPG
不过各种专利之争,只会导致推广受阻,我们还是想想怎么优化JPEG 和PNG 吧。
各种格式的介绍可以参考:《web前端图片极限优化策略》

Yelp 的图片优化经验

写这篇笔记,也是因为看到Yelp的一篇博文:Making Photos Smaller Without Quality Loss,然后延伸看了一些东西。Yelp的优化围绕JPEG和PNG,而且看起来很通用,值得学习。

用Pillow 优化图片

Yelp用Pillow来保存图片,Pillow支持optimize的参数:
optimize If present and true, indicates that the encoder should make an extra pass over the image in order to select optimal encoder settings.
另外也还有其他优化方式,例如大名鼎鼎的Tinypng智图等。推荐Pillow,Pillow的效果不差,而且开源、免费。

选择渐进式(Progressive) JPEG

常见的JPEG 有2种,基本式(Baseline)和渐进式(Progressive),明显的区别是前者从上至下加载,后者加载过程从模糊到清晰。 
渐进式一般会比基本式小一些,而且加载速度更快。
而且从用户体验上来说,从模糊到清晰比从空白展开到全部,前者体验更好。
关于为何渐进式会更小,需要从JPEG 的原理说起(对这一块也一知半解),JPEG被按照8x8,从坐标变换,DCT 变换,重排列,最后量化,得到的结果左上角是大量正数,右下角聚集大量0,然后再Zig-Zag 扫描,再用霍夫曼编码压缩。渐进式的情况下,相当于分层了,前面的扫描包含着大量正数,后面的扫描关注更多细节,包含大量的0,这样导致0 一起出现的概率增加,从而更易于压缩。
对此一知半解,看到DCT 变换,涉及到傅里叶变换,感觉高数都忘记了,惭愧,有兴趣的同学请自行阅读以下两份资料:

大尺寸的PNG 判断,然后转换为JPEG

PNG无损压缩,体积都很大,所以能不用PNG就不用,不过如果像Yelp这种,用户会上传PNG的话,例如iPhone的屏幕截图保存的格式就是PNG,完全可以转换为JPEG。Yelp遇到的问题是如果用户传的是LOGO之类的,需要无损,就不能转换成JPEG,所以他们想了一个办法:
生成一份PNG的缩略图,如果大于300KiB,再检查这个缩略图是否包含超过2^16种不同的色彩。一般来说LOGO的色彩都比较少和单一。

动态设置JPEG 质量因子(Quality)

JPEG有一个质量因子,从0到100,表示图片的质量从差到好。Yelp做了一个实验,发现在quality在80~85之间的时候,图片效果肉眼看基本没差别,SSIM在0.9~0.95。SSIM中文名称:结构相似性,用来判断两张图片的相似程度,拿一张压缩后的图片和原图比较,相似越高,说明失真越小,数学原理可以看维基百科,Yelp用pyssim来计算SSIM。
质量设置为80~85之间某一个值的时候,SSIM还能保持在0.9到0.95,多奇妙啊。Yelp提供了一段脚本来找出图片合适的quality值:dynamic_quality.py,用类似二分法猜数字的方法:P。
不过个人觉得对于一些色彩比较单一的图片,可以激进一点,例如从20~85开始找最合适的压缩比。为什么色彩单一的可以调低质量呢,因为肉眼看不出来啊。所以是不是可以延伸一下,用大量的训练数据,用AI的方法找到最合适的quality ?想起来Google之前推出的RAISR,非常厉害。
Yelp 博客提到的其他两篇相关文章,类似的思路,并且文中都有成型的开源工具:

其他

  • 用Mozjpeg 替代libjpeg-turbo 或libjpeg,性能提升明显。
  • Subsampling
  • 尝试有损的PNG 编码
  • SVG

No comments:

Post a Comment