fangpsh's blog

图片优化笔记

这里说的图片优化,目标是想尽可能降低图片大小,但又要保证质量不错,非常矛盾。不过降低图片大小,可以剩一大笔流量钱,降低负载,还能提升用户体验,值得花点功夫。

前端方面有一些关于图片加载速度的优化,例如CSS 画图,CSS 合并素材,甚至用CSS 把图片Base64 编码(不推荐),和这份笔记关系不大。

格式选择

不同的需求选择不同的格式, JPEG 能够满足的需求没必要选择PNG。

format-tree

图片来源:《web前端图片极限优化策略》,原图是Google 的Image Optimization

WebP、SharpP

目前对于WebP 的支持已经很好了,所以新业务能够选择WebP,就选WebP。
豆瓣的相册切到了WebP,另外提供了一个让图片变清晰的思路:把图片尺寸拉大到2倍,然后缩小成1倍。
图片清晰度大大提升,还降低了图片大小:2x WebP(73k) < 1x JPG(119k),效果如下图(图片来源 豆瓣 波希米亚的日记)。

douban.jpg

不过采用WebP 之后,用户“另存为”不太方便,毕竟大家对PNG和JPEG 比较熟悉。

豆瓣的WebP 实践:

有趣的是,WebP 基于VP8,VP8 的下一代是VP9,VP9 的对手是HEVC/H.265BGP 基于HEVC,据说表现比WebP 好很多,不知为啥应用不多,因为专利?

腾讯基于HEVC 搞出了一个SharpP 格式,听说秒天秒地,目前已在腾讯云CDN 上应用,不过接入的大都是腾讯自家的产品:

SharpP.jpg

图片模煳的没办法:( ,
图片来源:《图片流量节省大杀器:基于 CDN 的 sharpP 自适应图片技术实践》

看起来确实不错,听说在移动端解码速度也很快,不过如此大规模使用估计花了不少专利费。第三方用户使用也不方便,得使用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),明显的区别是前者从上至下加载,后者加载过程从模煳到清晰。参考下图: progressive

渐进式一般会比基本式小一些,而且加载速度更快。

speed

图片来源:《渐进式jpeg(progressive jpeg)图片及其相关》

而且从用户体验上来说,从模煳到清晰比从空白展开到全部,前者体验更好。

关于为何渐进式会更小,需要从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。

ssims-strategies

质量设置为80~85 之间某一个值的时候,SSIM 还能保持在0.9到0.95,多奇妙啊。Yelp 提供了一段脚本来找出图片合适的quality 值:dynamic_quality.py,用类似二分法猜数字的方法:P。

不过个人觉得对于一些色彩比较单一的图片,可以激进一点,例如从20~85 开始找最合适的压缩比。为什么色彩单一的可以调低质量呢,因为肉眼看不出来啊。所以是不是可以延伸一下,用大量的训练数据,用AI 的方法找到最合适的quality ?想起来Google之前推出的RAISR,非常厉害。

RAISR

扯远了。

Yelp 博客提到的其他两篇相关文章,类似的思路,并且文中都有成型的开源工具:

其他

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

目前,工作上没有实践的机会,纸上谈兵,希望以后有机会练手、实践。