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

前端方面有一些关于图片加载速度的优化,例如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),明显的区别是前者从上至下加载,后者加载过程从模煳到清晰。参考下图:

baseline-tiny progressive-tiny

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

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
  • 。。。

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