这里说的图片优化,目标是想尽可能降低图片大小,但又要保证质量不错,非常矛盾。不过降低图片大小,可以剩一大笔流量钱,降低负载,还能提升用户体验,值得花点功夫。
前端方面有一些关于图片加载速度的优化,例如CSS 画图,CSS 合并素材,甚至用CSS 把图片Base64 编码(不推荐),和这份笔记关系不大。
格式选择
不同的需求选择不同的格式, JPEG 能够满足的需求没必要选择PNG。
WebP、SharpP
目前对于WebP的支持已经很好了,所以新业务能够选择WebP,就选WebP。
豆瓣的相册切到了WebP,另外提供了一个让图片变清晰的思路:把图片尺寸拉大到2倍,然后缩小成1倍。
图片清晰度大大提升,还降低了图片大小:
豆瓣的相册切到了WebP,另外提供了一个让图片变清晰的思路:把图片尺寸拉大到2倍,然后缩小成1倍。
图片清晰度大大提升,还降低了图片大小:
2x WebP(73k) < 1x JPG(119k),效果如下图(图片来源豆瓣波希米亚的日记)。
不过采用WebP 之后,用户“另存为”不太方便,毕竟大家对PNG和JPEG 比较熟悉。
豆瓣的WebP 实践:
腾讯基于HEVC 搞出了一个SharpP 格式,听说秒天秒地,目前已在腾讯云CDN 上应用,不过接入的大都是腾讯自家的产品:
看起来确实不错,听说在移动端解码速度也很快,不过如此大规模使用估计花了不少专利费。第三方用户使用也不方便,得使用X5内核,且只能用腾讯云的CDN,这样被活活绑死的事情,愿意的人应该不多。另外腾讯还搞了一个TPG。
不过各种专利之争,只会导致推广受阻,我们还是想想怎么优化JPEG 和PNG 吧。
Yelp 的图片优化经验
写这篇笔记,也是因为看到Yelp的一篇博文:Making Photos Smaller Without Quality Loss,然后延伸看了一些东西。Yelp的优化围绕JPEG和PNG,而且看起来很通用,值得学习。
用Pillow 优化图片
optimize If present and true, indicates that the encoder should make an extra pass over the image in order to select optimal encoder settings.
选择渐进式(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的色彩都比较少和单一。
生成一份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