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

基础知识

常见图像格式对比

根据 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 的编码流程图:

输入为原始的 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 图片

图像压缩工具对比

平台/工具 类型 支持的图像格式 上传的单张图像限制大小 批量限制数 是否支持修改图像质量
Tinypng Web JEPG, PNG, GIF, WEBP 5M(付费版 75 M) 20 张(付费版无限制) 默认最佳质量
Tinypng 桌面端 - 破解版 Windows、Mac JEPG, PNG, GIF, WEBP 5M 无限制 默认最佳质量
shortpixel Web JEPG, PNG, GIF, WEBP 10 M(登录后 100 M) 50 张 默认最佳质量
Compressor.io Web JEPG, PNG, GIF, WEBP, SVG 10M(付费版 20 M) 10 张(付费版无限制) 默认最佳质量(付费版支持)
iloveimg Web JEPG, PNG, GIF, WEBP, SVG 5M 30 张 默认最佳质量
imageresizer Web JEPG, PNG, GIF, WEBP 100 M 50 张
Caesium Windows、Mac JEPG, PNG, GIF, WEBP 无限制 无限制
智图 Windows、Mac JEPG, PNG, GIF, WEBP 无限制 无限制
Win10 照片查看器 Windows JEPG, PNG, GIF , WEBP, ICO, TIFF, BMP 无限制 1 张

图像压缩工具实测

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

实测原图:

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

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

工具 JPG 图压缩后 (原 1.36MB) PNG 图压缩后 (原 369 KB) GIF 动图压缩后 (原 1.14 MB)
Tinypng 231 KB 70.6 KB -
shortpixel 198 KB 58.7 KB 472 KB
Compressor.io 177 KB 65 KB 601 KB
iloveimg 361 KB 69 KB 658 KB
imageresizer 270 KB 47.8 KB -
Caesium 236 KB 59.1 KB -
智图 183 KB 48 KB -
Win10 照片查看器 272 KB 292KB -

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

测试结果分析:

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

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

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

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

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

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

  1. 先获取 API KEY
  1. 各后端语言的教程 PHP, Node.js, Python, Java

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

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

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

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

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

  1. canvas 方向

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

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

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

  1. 算法方向

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

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

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

目前主流的图片压缩方案:localResizeIMGbrowser-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(鲁班):可能是最接近微信朋友圈的图片压缩算法

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

写在最后

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

参考文章

相关推荐
茶卡盐佑星_1 分钟前
说说你对es6中promise的理解?
前端·ecmascript·es6
Манго нектар29 分钟前
JavaScript for循环语句
开发语言·前端·javascript
蒲公英100136 分钟前
vue3学习:axios输入城市名称查询该城市天气
前端·vue.js·学习
天涯学馆1 小时前
Deno与Secure TypeScript:安全的后端开发
前端·typescript·deno
以对_1 小时前
uview表单校验不生效问题
前端·uni-app
程序猿小D2 小时前
第二百六十七节 JPA教程 - JPA查询AND条件示例
java·开发语言·前端·数据库·windows·python·jpa
奔跑吧邓邓子2 小时前
npm包管理深度探索:从基础到进阶全面教程!
前端·npm·node.js
前端李易安3 小时前
ajax的原理,使用场景以及如何实现
前端·ajax·okhttp
汪子熙3 小时前
Angular 服务器端应用 ng-state tag 的作用介绍
前端·javascript·angular.js
Envyᥫᩣ3 小时前
《ASP.NET Web Forms 实现视频点赞功能的完整示例》
前端·asp.net·音视频·视频点赞