前端性能优化系列 - 图像压缩篇

3,275 阅读12分钟

基础知识

常见图像格式对比

根据 caniuse 和 图像文件类型与格式指南 - MDN 网站提供的数据:

缩写摘要浏览器兼容性压缩透明度支持动画支持
JPEG静态图像有损压缩的理想选择(目前最流行)所有浏览器的所有版本有损压缩不支持不支持
PNG与 JPEG 相比,PNG 能更精确地再现源图像,或在需要透明的情况下更受青睐除了 IE6 以外的所有浏览器的所有版本无损压缩支持不支持
GIF是简单图像和动画的不错选择所有浏览器的所有版本无损压缩支持支持
WebP是静止图像和动画图像的【绝佳选择】,WebP 的压缩效果比 PNG 或 JPEG 好得多,而且支持更高的色深、动画帧和透明度等
  • Chrome: 32+
  • Edge: 18+
  • Firefox: 65+
  • Safari: 14+
  • Opera: 19+
有损和无损压缩支持支持
SVG矢量图像格式;适用于用户界面元素、图标、图表等,必须以不同尺寸精确绘制
  • Chrome: 28+
  • Edge: 12+
  • Firefox: 4+
  • Safari: 9+
  • Opera: 10+
可使用 HTTP 压缩技术进行压缩支持支持
APNG
  • 动态的 PNG
  • 性能:WEBP>APNG>GIF
  • 兼容性:GIF>APNG>WEBP
  • Chrome: 59+
  • Edge: 12+
  • Firefox: 3+
  • Safari: 8+
  • Opera: 46+
无损压缩支持支持

其中,WebP 格式是由谷歌于 2010 年推出的图像文件格式,其目的在于取代网络上的 JPEG 和 PNG 格式。WebP 格式均支持有损压缩和无损压缩,压缩率高于常用的 JPEG 和 PNG 格式;
它还提供动画功能,可以替代 GIF 动图。基本上,动画 WebP 文件的大小比相同内容的 GIF 文件小 1/5 至 1/10;
目前来看,WEBP 图像除了兼容性的问题,其余都是优点

调整图像尺寸/格式

假设原图尺寸是 6000 × 4000,这样的超清图像尺寸不建议直接压缩,可以先在前端页面中评估一下所需的最大尺寸,如果允许尺寸缩小,先把图像尺寸改小再进行压缩,综合来看压缩率更高

重设图片分辨率的方法有如下几种方式:

工具/平台类型功能是否支持批量
windows 照片应用程序windows转换格式(JPEG、PNG 之间互转)、调整尺寸不支持
Mac 照片应用程序Mac调整尺寸不支持
imageresizer在线网站转换格式(JPEG、PNG、WEBP 之间互转)、调整尺寸支持
convertio在线网站转换格式(任意格式互转)支持
iloveimg在线网站调整尺寸支持

图像压缩原理

图像压缩的本质是:减少表示数字图像时需要的数据量

图像数据之所以能被压缩,就是因为数据中存在着冗余,主要表现为:

  • 图像中相邻像素间的相关性引起的空间冗余
  • 图像序列中不同帧之间存在相关性引起的时间冗余
  • 不同彩色平面或频谱带的相关性引起的频谱冗余

数据压缩的目的就是通过去除这些数据冗余来减少表示数据所需的比特数

有损压缩和无损压缩

无损压缩

举例来说,对于这样一组数据9 5 5 5 7 8 8 8 8 8 ,假如我们使用 RLE 游程编码,无损结果为:1 9 3 5 1 7 5 8 分别表示1个9,3个5,1个7,5个8。
原始数据为10个数,RLE压缩结果为8个数,压缩率为(10 – 8)/ 10 = 20%
当对这个数据进行解码时,按同样的规律即可将1 9 3 5 1 7 5 8 展开为9 5 5 5 7 8 8 8 8 8
由于解码后的数据与最初的输入数据完全一致,因此这种RLE的压缩方式为无损压缩,即整个过程没有信息丢失。

有损压缩

同样对于输入数据9 5 5 5 7 8 8 8 8 8,假如我们考虑量化(所谓量化通常是指将一个较大的数域映射到较小的数域上),量化的方式为除3取整。量化后的结果为:3 2 2 2 2 3 3 3 3,然后RLE游程编码结果为:1 3 4 2 5 3分别表示1个3,4个2,5个3。
原始数据为10个数,压缩后为6个数,压缩率为(10-6)/10=40%。
当对这个数据解码时,按同样的规律可将1 3 4 2 5 3 展开为9 6 6 6 6 9 9 9 9 9

JPEG 编码

前面说到,JPEG 是一种有损压缩格式,通常比 PNG(无损压缩)具有更小的文件大小。将 PNG 图像转换为 JPEG 可能会显著减小文件大小。根本原因在于:JPEG 的编码方式本身就是一个有损压缩的过程

以下是 JPEG 的编码流程图:

image.png

输入为原始的 RGB 数据,输出为 JPEG 图片

  1. 颜色转换

是指由RGB的色彩空间转换成YUV的色彩空间,Y代表像素的亮度,UV分别代表色调和色饱和度
进行色彩空间转换主要是因为YUV的色彩空间更符合人类视觉,人类的眼睛对于亮度差异的敏感度高于色彩的变化。也就是说人眼对UV不够敏感,即使丢掉一部分信息,也不会察觉

  1. 色彩抽样

如上所说,因为人眼对色彩的变化不敏感,因为为了提高压缩率,会在UV通道上进行抽样压缩。在JPEG中常见的下采样有4:4:4,4:2:2,4:1:1。
对色度进行下采样,压缩后的文件大小会有明显减小,同时也可能会对图片的质量产生影响

  1. 分块

为了减少编码过程的计算量,实现快速计算,因此需要对原图像进行分块,对每一个分块再进行DCT变换。在JPEG中,分块大小为8x8。同时分块以后,量化也比较容易做,对一整幅图直接进行量化,效果偏差很大

  1. DCT 变换(离散余弦变换)和量化

DCT变换是JPEG压缩的数学基础,也是JPEG压缩最核心的部分。DCT变换本身是无损的,经过IDCT变换(逆DCT变换)就可将数据恢复
DCT变换简单来说就是矩阵变换,把一个数据量大的矩阵变换成数据量小的矩形,详细参考 离散余弦变换

处理前:

处理后:

  1. Huffman 编码(哈夫曼编码)

Huffman编码的思想是将数据中出现最多的字符用最小的长度去表示。一般情况下,Huffman编码都能取得较高的压缩率在JPEG实现的时候,对于DC系数(左上角的那一个元素)和AC系数(剩下的的63个元素)采用了不同的处理。对DC系数使用DPCM(差分脉冲调制码),用当前的DC减去前一个子图的DC,然后使用Huffman编码。对AC系数,则使用Zig-Zag方式扫描,然后使用Huffman编码。Zig-Zag方式扫描示意图如下:

Huffman编码的效果直接影响文件的大小,一般情况下,所有的图片都可以进行Huffman编码优化,也即通常所说的JPEG无损处理,提升的压缩率为0%-5%左右。

以上Huffman编码的结果,再配合文件头的描述、量化表的信息就构成了我们看到的 JPEG 图片

图像压缩工具对比

平台/工具类型支持的图像格式上传的单张图像限制大小批量限制数是否支持修改图像质量
TinypngWebJEPG, PNG, GIF, WEBP5M(付费版 75 M)20 张(付费版无限制)默认最佳质量
Tinypng 桌面端 - 破解版Windows、MacJEPG, PNG, GIF, WEBP5M无限制默认最佳质量
shortpixelWebJEPG, PNG, GIF, WEBP10 M(登录后 100 M)50 张默认最佳质量
Compressor.ioWebJEPG, PNG, GIF, WEBP, SVG10M(付费版 20 M)10 张(付费版无限制)默认最佳质量(付费版支持)
iloveimgWebJEPG, PNG, GIF, WEBP, SVG5M30 张默认最佳质量
imageresizerWebJEPG, PNG, GIF, WEBP100 M50 张是
CaesiumWindows、MacJEPG, PNG, GIF, WEBP无限制无限制是
智图Windows、MacJEPG, PNG, GIF, WEBP无限制无限制是
Win10 照片查看器WindowsJEPG, PNG, GIF, WEBP, ICO, TIFF, BMP无限制1 张是

图像压缩工具实测

实测关注指标:压缩率和压缩后的视觉效果

实测原图:

  • 1.36 MB 的 JPG 格式的不透明静态图像
  • 369 KB 的 PNG 格式的半透明静态图像
  • 1.14 MB 的 GIF 格式的半透明动态图像

image.png image.png

同样的 3 张原图压缩后大小如下:(压缩质量统一 80 %,如果不能修改就是工具默认的)

工具JPG 图压缩后
(原 1.36MB)
PNG 图压缩后
(原 369 KB)
GIF 动图压缩后
(原 1.14 MB)
Tinypng231 KB70.6 KB-
shortpixel198 KB58.7 KB472 KB
Compressor.io177 KB65 KB601 KB
iloveimg361 KB69 KB658 KB
imageresizer270 KB47.8 KB-
Caesium236 KB59.1 KB-
智图183 KB48 KB-
Win10 照片查看器272 KB292KB-

PS:压缩后的图就不放上来了,平台会再次压缩导致肉眼看不出差别

测试结果分析:

  • 压缩后的 JPG 中,肉眼可见 智图 的图像质量较差,Compressor 的图片质量较佳,同时也是压缩率最高 87.3%
  • 压缩后的 PNG 中,肉眼看不出图像质量的区别,压缩率最高的是 imageresizer 87.0%
  • 压缩后的 GIF 中,肉眼看不出图像质量的区别,压缩率最高的是 shortpixel 59.6%

注:此为测试图的测试结果,仅供参考

拓展 - 后端压缩技术/工具

ImageMagick 是一个功能强大的命令行图像处理工具,支持 PHP、Python、Ruby、Node.js 等多种后端语言,支持 JPEG、PNG、GIF 等多种图像格式和操作,包括压缩和优化。支持有损和无损图像压缩

image.png

Pillow 是 Python 的一个图像处理库,是 Python Imaging Library(PIL)的一个分支。Pillow 支持多种图像格式,包括 JPEG、PNG、GIF,并提供了图像压缩和优化功能。

image.png

Tinypng 平台提供 API 供开发者调用,支持 PHP, Node.js, Python, Java 多种后端语言,支持压缩 JPEG、PNG、WEBP 格式的图像,按压缩次数收费,收费标准:

image.png
  1. 先获取 API KEY

image.png

  1. 各后端语言的教程 PHP, Node.js, Python, Java

PS:这是在网上找到的支持 Node.js 的破解版

image.png

拓展 - 前端压缩技术/工具

以下部分内容来源于 juejin.cn/post/731163…

基于当前由后端压缩的图片,图片请求时会产生302的情况,导致页面加载速度变慢,以及前端传输未压缩的图片会占用服务器更多带宽等方面的考量。所以也可以考虑直接在前端进行图片压缩

前端图片压缩实现方向有两个:

  1. canvas 方向

利用 Canvas 的绘图能力,使用 drawImage 以及 toDataURL 这两个 API,通过调整图片的尺寸或者绘图质量,来达到图片压缩的效果。

  • 优点:实现简单,参数可配置化,可自定义图片尺寸,指定区域裁剪等等。
  • 缺点:只有 jpeg 、webp 支持原图尺寸下图片质量的调整,来达到压缩图片的效果,其他图片格式仅能通过调整尺寸来实现。

基于 canvas 技术的开源库有:imgResize

image.png

  1. 算法方向

简单来说,通过算法减少图片上的颜色差异,牺牲图片画质。比如紧挨着的颜色相近的四个像素的颜色信息压缩前大概占16个字节,压缩后变成一个颜色就能减少近4倍。自然被压缩后文件就变小,画质自然也会降低。

  • 优点:色彩丰富场景压缩率更高,参数可配置化,可自定义图片的尺寸,图片的质量等。
  • 缺点:图片质量压缩损失更大。

由于 canvas 技术压缩图片的能力有限,所以放弃自行开发,寻找开源库来完成能更好地解决问题

目前主流的图片压缩方案:localResizeIMG、browser-image-compression

localResizeIMG 不支持压缩半透明的图片,在无需考虑透明的情况下选择 localResizeIMG 最优

browser-image-compression 压缩PNG格式插件。PNG格式的图片特点,高保真,支持透明度处理,但是它也有明显的问题就是体积过大。不过在经过 browser-image-compression 压缩后,PNG 格式的图片体积过大的缺点会得到十分有效的改善。

对比原图、Tinypng、browser-image-compression 压缩插件

压缩工具显示效果体积大小压缩图
原图★★★★★★531 KB左图
Tinypng(作参照)★★★★★★★★★118 KB中图
browser-image-compression压缩插件★★★★★★★★79.0 KB右图

图片压缩流程

  • 获取上传的图片文件

    • 点击上传: 点击上传使用的是 choose-to-file 实现点击上传功能获取上传文件。
    • 拖拽上传:使用的是drop事件获取上传文件,同时使用dragover、dragleave事件判断拖拽进入和离开。
    • 复制上传,利用的是 paste事件 监听window的粘贴事件,从而获取到上传文件。
  • 使用 browser-image-compression 进行压缩

  • 调用接口,上传压缩后的图片文件

拓展 - 客户端压缩技术/工具

  • Luban——Android 图片压缩工具

Luban(鲁班):可能是最接近微信朋友圈的图片压缩算法

image.png

WCImageCompress:图片大小质量压缩,非常接近微信

image.png

写在最后

如果还有哪些图片压缩工具好用的欢迎在评论区推荐一下,如果我文章里推荐的工具有哪些不好用的话也欢迎在评论区指出~

参考文章