Web 优化:图片压缩简介
发布时间:
最后更新:
作为一个有强迫症的人,我对应用的性能相当敏感。众所周知多媒体资源是网页里最耗流量的,其中最常用的图片自然就成了优化的重点,我的博客图还是挺多的,所以在图片优化这一块下了大功夫。
首先把结果摆出来,相当好:
压缩方式 | 压缩率 % |
---|---|
AVIF | 5.73 |
WebP | 13.8 |
Pngquant | 34.74 |
Mozjpeg | 39.49 |
SVGO | 65.56 |
SVGO + brotli | 16.47 |
以上是本站目前全部 155 张的图片统计,压缩率指优化后的体积 / 原图体积
,越低越好。
图片优化这块还是有很多细节和坑,我准备写一系列的文章,把我的经验都分享出来。本文是此系列的第一篇,主要对图片的压缩方案做介绍。
优化思路 #
要做图片优化,首先得了解主流四大格式:
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 因为不支持透明。
JPG 图基本都是高压缩率的,但由于各种编码器实现不同,所以还有二压的空间,通过更先进的编码器重新压缩,可以实现较小的失真下继续降低体积。
另外不要对二压有恐惧,只要用好的编码器、调好参数基本不会有多大的质量损失,那个图片越压越绿纯粹是安卓编码器的 BUG。
SVG 不同于光栅图,对其的优化主要从两个方面入手:
-
写法转换,删除无用的信息。就跟 JS 的压缩一样,同样的效果换一种写法可能就短一点;另外还可以删减小数位数,不过这是有损的一般不用。JS 平台就有压缩 SVG 的库 SVGO。
-
SVG 是基于 XML 的,说白了就是文本,所以优化完了还可以再拿文本压缩算法压一遍,浏览器支持的算法有 zip、gzip 和新一代的 brotli。
GIF转视频 #
GIF 图质量之差,体积之大相信大家都体验过,它还能活着只因为有动图的功能,不过仔细想一想动图跟视频不就是一回事吗,视频还可以多个声音。
GIF 图之所以现在还能见到,全靠当年的浏览器不支持视频,如今已进入视频时代,是时候淘汰掉 GIF 了,无论是主流的 AVC、没人鸟的 HEVC 还是下一代的 VVC 视频编码都比它先进得多。
即使不想转视频,也是有 Gifsicle 这样的工具可以压缩 GIF 图的。
使用新一代编码 #
上面讲到主流的格式都是上个世纪的东西,软件技术发展这么快,当然会有新的算法出现啦,接下来就说一说这些新的编码。
这里的新一代编码指 2000 年以后发明的,且被(或未来可能被)浏览器广泛支持的编码。
新一代的图片编码都是从视频编码衍生出来的,因为视频就是一连串图片,视频编码自然包含了对图片压缩的部分(帧内编码)。新一代的图片编码都同时支持透明度和动画,所以没有必要再分出三种格式了。
WebP #
WebP 是 VP8 视频编码衍生出来的,目前已经被广泛的接受(全靠他 Google 爹的垄断浏览器),成为了新一代的前端图片格式。
作为新一代编码(其实也不新了),WebP 对大多数图片有着更好的压缩率和图片质量。这里有一个把图片压到相同的质量下,以 JPG 为基准,WebP 和 AVIF 图片体积的对比:
可以看到 WebP 的体积通常比 JPG 小 30%,所以给图片转码个 WebP 作为渐进增强是十分有价值的。
下面那 2.7% 负优化情况在本文后面会有讲解。
AVIF #
AVIF 是 AV1 视频编码对应的图片格式,AV1(对应VP10) 是 VP8 的下两代,AVIF 也就成为了 WebP 的继任者,它拥有比 WebP 更高的压缩率和更好的质量。
在上面的对比图里 AVIF 压缩率比 WebP 高了 20%,而且没有负优化的情况。
不过目前 AVIF 的生态还未成型,在写本文时 AVIF 正迎来一个爆发期,各种评测层出不穷,可见其受欢迎的程度。
未来的编码 #
H.266 / VVC #
视频和图片的压缩还远未达到终点,新的技术正在不断的开发。从 2015 年 10 月开始的新一代的视频编码 H.266/VVC 前不久终于确定了标准,不知道会不会像 HEVC 一样推出图片编码呢。
JPEG XL #
编码的竞争如此激烈,以至于 JPEG 专家组也坐不住了,于 2017 年推出了新的编码,JPG 的正统继承者 JPEG XL。在同样支持一堆新特性及更高的压缩率的同时,还向后兼容 JPEG 解码器,升级更加顺滑。
WebP 2 #
https://chromium.googlesource.com/codecs/libwebp2
WebP 的第二代,2020 年 10 月开始的新项目,目标是进一步提高压缩率(+30%)以及支持新一代图片特性(10bit HDR)。因为 WebP 的效果不错所以下一版也是很值得期待的。
没能成为主流的编码 #
顺便提一下那些没能火的,这些编码也有很好的压缩率,但是因为一些原因与主流支持失之交臂。
-
JPEG2000:2004年的编码,目标是取代 JPG,但是由于专利问题而缺乏互联网生态的支持,不过在其他领域还是有一席之地的。
-
APNG:Mozilla 开发的编码,兼容 PNG 还支持动画,但可惜以 Mozilla 的实力是没法推广的。
-
JPEG XR:2009 年由微软推出的编码,由于当时微软的名声差,以及没有 Chrome 这样的垄断平台推广,所以只能遗憾的退出历史的舞台。
-
HEIF:X.265/HEVC 对应的图片编码,2015 年完成,但是 HEVC 有专利问题,目前只有苹果家的浏览器支持。
-
BGP:2014 年由几个大牛设计的,但可惜沾了 HEVC 的技术,于是同样死于专利。
从上面这些嗝屁的编码中,可以总结出被广泛支持需要的的两个条件:
-
开放专利,如果有专利问题各大厂商肯定会犹豫,只有开放的技术才有可能成为主流。
-
谷歌支持,浏览器上的技术,只要没有没有谷歌爸爸的肯首,那肯定是火不起来的,毕竟主流浏览器内核 = Chromium。
总结一下 #
画个流程图就是这样了,当然这里面还有很多细节问题需要处理,在后续的文章中再做讲解。
免费工具推荐:
- ICAnalyzer 我开发的一款工具,主要目标是对比各个转换器的效果,当然也能用来压缩图片。
- pngquant 是一款有损压缩 PNG 的工具,通过减少图片使用的颜色数量来降低体积,即量化(quantise),对 PNG 的有损压缩基本都使用了这个变换。
- MozJPEG 是 JPG 格式转换器中的佼佼者,即使是 JPG 格式的图片用它二压通常也有效。
- Website Planet 是一个免费的在线工具,能批量压缩 JPG 和 PNG。
- Squoosh Google 出品的在线图片转换器,支持除 GIF 外的所有主流格式,还提供了 NPM 包方便集成到自己的项目中。选择 Reduce palette 和 OxiPNG 即可压缩 PNG。
WebP 的缺陷 #
通常 WebP 被视为传统格式的替代者,但在实际使用中我发现它并不一定比旧格式更好。
这个图就是本站在宽屏下最顶部的 Banner,压出来的结果不是很好,可以看到斜边和阴影产生了严重的马赛克。
我统计了博客里所有的图,发现 WebP 有损压缩对锐利的边缘失真严重,并增加体积,这可能是算法本身的缺陷。
另外 WebP 压缩后的图片甚至能比原图还大,在官网上也有对此的描述:can_a_webp_image_grow_larger_than_its_source_image
举个例子,在本站的一张图上:
左边的是有损模式,可以看到红色的字符串、紫色的关键字、以及绿色的注释部分都有色彩失真,而且文件体积是无损模式的7倍。有损压缩我还加了-sharp_yuv
参数的,要是没这个参数那简直没法看。
你可以自己尝试一下,把这张图 上传到 Squoosh 并选择 WebP Compress,看看它是怎么把你的图压成一坨屎的。
因为有这些问题,所以不能无脑把所有图片全用 cwebp 默认参数直接压。
这个的解决方案在我的另一篇文章《WebP 参数分析》里有解释,就是同时使用无损和有损压缩,然后选择体积更小的。
渐进式图片? #
渐进式指先显示模糊版,随着加载逐渐清晰的图片。我经常听到有人吹渐进式图片,说先显示一个模糊图体验更好,但我怀疑他们没有真的想过这个问题。
一张全是马赛克的图能看吗?相反,非渐进式的载入到一半起码还能看一部分。
很多图片比如漫画、文字类的,其局部就包含独立的信息,非渐进式的能边加载边看,而渐进式图片在完成之前只能傻等。
当然这是我的经验,我眼睛没有从一张马赛克图还原出原图的能力,也许那些吹渐进式图片的人有。所以以载入体验更好的理由使用渐进式图片是站不住脚的。
当然这并不意味着渐进式就一无是处,它对体积是影响的,还是统计博客里所有的图,测试 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 许可。
图片《视频编码器的历史》没能找到原作者。