Web图片优化(一):压缩方案简介

发布时间:

最后更新:

关键词: AVIF SVG WebP 图片优化

作为一个有强迫症的人,我对应用的性能相当敏感。众所周知多媒体资源是网页里最耗流量的,其中最常用的图片自然就成了优化的重点,我的博客图还是比较多的,所以在开发时在图片优化这一块下了大功夫。

首先把结果摆出来,相当好:

压缩方式 压缩率 %
WebP 13.8
Pngquant 34.74
Mozjpeg 39.49
SVGO 65.56
SVGO + brotli 16.47

以上是本站目前全部155张的图片统计,压缩率指优化后的体积 / 原图体积,越低越好。

图片优化这块还是有很多细节和坑,我准备写一系列的文章,把我的经验都分享出来。本文是此系列的第一篇,主要对图片的压缩方案做介绍。

TODO:接下来的两篇正在龟速撰写中,(1)图片的压缩和下载方式选择,(2)WebP 编码器调参。

优化思路

要做图片优化,首先得了解主流四大格式:

  • png Portable Network Graphics, 1996年发明的编码,支持透明。
  • jpg Joint Photographic Experts Group,是1992年发明的。
  • gif Graphics Interchange Format,1987年的老古董,质量极差,但是可以组合多张图成为动画。
  • svg Scalable Vector Graphics,2001年发布初始版本,这是矢量图,优化方式是不同于上面三种光栅图的。

现在网页上用的图基本就是这四个,都是很多年前的东西了。

相同格式的优化

PNG 大多用来保存原图,这类图片质量一般都很高,但相对的压缩率就不那么高了,用来存档还行,放在网络上传输有点浪费流量。

通常 PNG 被称作无损格式,实际上这个说法是错误的,有没有损取决于转换过程中是否改变了原图的信息,而不是格式本身。换句话说,是否无损要看转换工具有没有做有损变换。

从感官学上讲,一点点的失真是可以接受的,毕竟大多数用户不会拿着放大镜看你的图,真要原图也可以单独提供下载,把 PNG 图有损压一下可以大幅降低文件体积。当然压缩的结果必须仍是 PNG 图,不能转 JPG 因为不支持透明。pngquant 就是这么一款有损压缩 PNG 的工具。

JPG 图基本都是高压缩率的,但由于各种编码器实现不同,所以还有二压的空间,通过更先进的编码器重新压缩,可以实现较小的失真下降低不少的体积Mozjpeg 就是其中的佼佼者。

另外不要对二压有恐惧感,只要用好的编码器、调好参数基本不会有多大的质量损失,那个图片越压越绿纯粹是安卓编码器的BUG

SVG 不同于光栅图,对其的优化主要从两个方面入手:

  1. 写法转换,删除无用的信息。就跟 JS 的压缩一样,同样的效果换一种写法可能就短一点;另外还可以删减小数位数,不过这是有损的一般不用。JS 平台就有压缩 SVG 的库 SVGO

  2. SVG 是基于 XML 格式的,说白了就是文本,所以还是跟 JS 一样优化完了还可以再拿文本压缩算法压一遍,浏览器支持的算法有 zip、gzip 和新一代的 brotli。

GIF转视频

GIF 图质量之差,体积之大相信大家都体验过,它没被淘汰只因为有动图的功能,不过仔细想一想动图跟视频不就是一回事吗,视频还可以多个声音。

GIF 图之所以现在还能见到,全靠当年的浏览器不支持视频,如今已进入视频时代,gif图应当用视频来替代,无论是主流的 AVC、没人鸟的 HEVC 还是下一代的 VVC 视频编码都比1987年的 GIF 先进得多。

即使不想转视频,也是有 Gifsicle 这样的工具可以压缩 GIF 图的。

使用新一代编码

上面讲到主流的格式都是上个世纪的东西,软件技术发展这么快,当然会有新的算法出现啦,接下来就说一说这些新的编码。

这里的新一代编码指2000年以后发明的,且被(或未来可能被)浏览器广泛支持的编码。

视频编码的历史 视频编码的历史

新一代的图片编码都是从视频编码衍生出来的,因为视频就是一连串图片,视频编码自然包含了对图片压缩的部分(帧内编码)。新一代的图片编码都同时支持透明度和动画,所以没有必要再分出三种格式了。

WebP

WebP 是 VP8 视频编码衍生出来的,目前已经被广泛的接受(全靠他 Google 爹的垄断浏览器),成为了新一代的前端图片格式。

自从 Safari14 宣布了支持 WebP 图像,WebP 完成了全平台制霸(IE已被我开除浏览器籍)。

WebP的兼容性 WebP的兼容性

作为新一代编码(其实也不新了),WebP 对大多数图片有着更好的压缩率和图片质量。这里有一个把图片压到相同的质量下,以 JPG 为基准,WebP 和 AVIF 图片体积的对比:

AVIF and WebP vs JPEG AVIF and WebP vs JPEG

可以看到 WebP 的体积通常比 JPG 小30%,所以给图片转码个 WebP 作为渐进增强是十分有价值的。

下面那 2.7% 负优化情况在本文后面会有讲解。

AVIF

AVIF 是 AV1 视频编码对应的图片格式,AV1(对应VP10) 是 VP8 的下两代,AVIF 也就成为了 WebP 的继任者,它拥有比 WebP 更高的压缩率和更好的质量。

在上面的对比图里 AVIF 压缩率比 WebP 高了 20%,而且没有负优化的情况。

AVIF兼容性 AVIF兼容性

因为比较新,兼容性上自然没有 WebP 那么乐观,Chrome 和 Firefox 都提供了支持;套壳浏览器 Edge 使用的是 Chrome 的内核所以也会支持的;苹果同样是 Alliance for Open Media 的成员,Safari 的支持只是时间问题。可以肯定的是 AVIF 将成为下一个被广泛使用的图片编码。

不过目前 AVIF 的生态还未成型,Netflix 等大厂支持 AV1 也都是今年才开始的。在写本文时 AVIF 正迎来一个爆发期,各种评测层出不穷,可见其受欢迎的程度。

不过本站目前没有使用 AVIF 图,不是我不想用,而是在测试时出现了一些问题:

  • NodeJS 生态欠缺,没有找到本地的编码器扩展,WASM 倒是试了两个:@saschazar/wasm-avifsquoosh 感觉不是很好用,前者有内存错误后者没提供 npm 包不好管理。当然还有一种选择是调用外部编码程序。

  • 压缩率不理想,在测试中全部155张图里只有极个别压缩率和质量超过 WebP,大部分体积反而比 WebP 大了好几倍。当然我还没有研究 AVIF 的转换参数,不知道 Netfilx 他们是用得什么参,也没有找到调优方面的文章。

特别是第二条让我暂停了对 AVIF 的使用,先研究研究再说。

未来的编码

视频和图片的压缩还远未达到终点,新的技术正在不断的开发,目前最新一代的视频编码 H.266/VVC 前不久确定了标准,不知道VVIF是否能被广泛支持。

AV1 的下一代 AV2 的研发工作也已经开始。在未来,图片和视频到底能被压到何种程度,让我们拭目以待。

没能成为主流的编码

顺便提一下那些没能火的,这些编码也有很好的压缩率,但是因为一些原因与主流支持失之交臂。

  • JPEG2000:2004年的编码,目标是取代 JPG,但是由于专利问题而缺乏互联网生态的支持,不过据说在其他领域还是有一席之地的。

  • APNG:Mozilla 开发的编码,兼容 PNG 还支持动画,但可惜以 Mozilla 的实力是没法推广的。

  • JPEG XR:2009 年由微软推出的编码,由于当时微软的名声差,以及没有 Chrome 这样的垄断平台推广,所以只能遗憾的退出历史的舞台。

  • HEIF:X.265/HEVC 对应的图片编码,2015 年完成,但是 HEVC 的专利你懂的,目前只有苹果家的浏览器支持。

  • BGP:2014 年由几个大牛设计的,但可惜沾了 HEVC 的技术,于是同样死于专利。

从上面这些嗝屁的编码中,可以总结出被广泛支持需要的的两个条件:

  1. 开放专利,如果有专利问题各大厂商肯定会犹豫,只有开放的技术才有可能成为主流。

  2. 谷歌支持,浏览器上的技术,只要没有没有谷歌爸爸的肯首,那肯定是火不起来的,毕竟主流浏览器内核 = Chromium

总结一下

流程图 流程图

画个流程图就是这样了,当然这里面还有很多细节问题需要处理,在后续的文章中再做讲解。

WebP 的缺陷

通常 WebP 被视为传统格式的替代者,但在实际使用中我发现它并不一定比旧格式更好。

WebP的质量损失 WebP的质量损失

这个图就是本站在 PC 上最顶部的 Banner,压出来的结果不是很好,可以看到斜边和阴影产生了严重的马赛克。

我统计了博客里所有的图,发现 WebP 有损压缩对锐利的边缘失真严重,并增加文件体积,这可能是算法本身的缺陷。

另外 WebP 压缩后的图片甚至能比原图还大,在官网上也有对此的描述:can_a_webp_image_grow_larger_than_its_source_image

举个例子,在本站的一张图上:

WebP两种压缩对比 WebP两种压缩对比

左边的是有损模式,可以看到红色的字符串、紫色的关键字、以及绿色的注释部分都有色彩失真,而且文件体积是无损模式的7倍。有损压缩我还加了-sharp_yuv参数的,要是没这个参数那简直没法看。

你可以自己尝试一下,把 这张图 上传到 squoosh 并选择 WebP Compress,看看它是怎么把你的图压成一坨屎的。

因为有这些问题,所以不能无脑把所有图片全用 cwebp 默认参数直接压。

那么怎么解决呢,目前我的方案是根据文件体积增加这一特征来检测。当一张图上传后,如果是PNG(JPG 很少出现此问题)则同时使用有损和无损两种模式压缩,然后选择体积小的一个。

这样无论是插画还是文字都能很好地处理,但如果遇到混合的那就无效了,不过这种情况应该很少。

渐进式图片?

渐进式指先显示模糊版,随着加载逐渐清晰的图片。我经常听到有人吹渐进式图片,说先显示一个模糊图体验更好,但我怀疑他们没有真的想过这个问题,而是从别处抄来的这个说法。

一张全是马赛克的图那能看吗?相反,非渐进式的图载入到一半起码还能看一部分。

很多图片比如漫画、文字类的,其局部就包含独立的信息,非渐进式的能边加载边看,而渐进式图片在它全部加载完之前只能傻等。

当然这是我的经验,我眼睛没有从一张马赛克图还原出原图的能力,也许那些吹渐进式图片的人有。所以以载入体验更好的理由使用渐进式图片是站不住脚的。

当然这并不意味着渐进式就一无是处,再看看渐进式对体积的影响,还是统计博客里所有的图,测试 JPG(Mozjpeg 的-progressive 选项),和 PNG(libpng 的 interlace选项)使用和不使用时转换结果的大小,结果:

  • 渐进式 JPG 比非渐进式的体积小 13.66%

  • 渐进式(交错) PNG 比非渐进式的体积大 15.62%

这十几个点的体积还是有影响力的,所以为了压缩率,JPG 应当使用渐进式而 PNG 不能用。 顺便一提 WebP 和 AVIF 都没有渐进式这功能。

版权声明

图片 AVIF and WebP vs JPEG 来自 Comparing AVIF vs WebP file sizes at the same DSSIM,作者 Daniel Aleksandersen 使用 CC BY-SA 4.0 许可。

图片 视频编码器的历史 没能找到原作者。

评论加载中