抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

前言 为什么会有这篇文章

事情是这样的:一天傍晚,我正在为博客寻找新的头图老婆,于是便找到了这张图片:

(该图片经过压缩,非原始图片)

由于原图是 3072×2280 的,体积高达 4.59M,对于网站来说,显然是太过巨大了,因此我便着手开始寻找网页图片压缩的网站/API。

一开始,我选择以 PNG 格式进行压缩,因为据称 PNG 格式的损失率更小、且支持 Alpha 通道颜色存储(即支持带透明度的颜色)。我得到了下面大小为 900K 的输出图像:

乍一看,好像都差不多。可是根据图像压缩网站的分析,我的原图有 44w+ 种不同的 RGB 颜色,但 PNG 模式最多仅能保留 256 种颜色(最低保留 8 种颜色,效果不忍直视,就不放了,但体积只有 240M 左右)。这意味着我的原图的很多渐变的颜色被压缩算法统一抹成了同种颜色,具体可以看到白洲梓脸颊的红晕部分:

我就是要看红晕的结果你给我压缩成这幅鬼样子……

可以很明显地看出差别——压缩后的图片中,脸颊的红晕原本是由大量渐变颜色画成的,然而压缩为 256 色后明显的失去了渐变效果,取而代之的是明显的锯齿感、以及扎眼的色彩偏差(具体见蝴蝶结部分)。尽管压缩保持了原图片的尺寸,但是 PNG 模式压缩对细节的保留是极简的,计算不难发现,色彩数变成了原先的 ,效果可想而知……8 RGB颜色的图片看上去和遗照已经没两样了……

因此这篇文章用来探讨 JPEG 和 PNG 图像格式的压缩效果差异,并给出我个人关于网页图片压缩处理的一些经验建议。

第一节——PNG 是什么,以及它是如何压缩的

PNG 全称 Portable Network Graphics,即可移植网络图形格式,由 W3C 在 1994 年开发,最初设计来为当时的 GIF 图像提供一种现代的、免费的替代方案。与 GIF 格式相比,二者虽然都内置了一个 Alpha 颜色通道用来记录透明颜色,但是 GIF 仅允许一种全透明颜色、而 PNG 支持任意百分比透明度的 RGB-Alpha(后简称 RGBA) 颜色。由于 PNG 格式压缩的无损性,在此后的数十年里,它被广泛用作网络的图像传输;当然它也有劣势,就是图像体积远大于 JPG 格式的图像。

既然 PNG 是无损压缩,那为什么压缩出图的质量还这么拉胯呢?

问题出在压缩的颜色数量上,正如上文所述,PNG 模式压缩最高支持到 256 色。在压缩算法进行时,算法会对图片文件进行逐行扫描,并分别采用最优压缩方案。当然,这种处理模式的上限是仅保留 256 种不同的颜色,对于相邻且差距不大的颜色块,算法作统一化处理,将这块区域涂成同样的颜色。自然就会出现颜色间出现明显断层、偏差的现象。

如果你也有这样一张颜色丰富的图像急需压缩的话,推荐使用 JPEG 格式压缩,见下文:

第二节——JPEG是什么,以及它是如何压缩的

JPEG 全称 Joint Picture Expert Group,即联合图像专家组。它和我们更常见到的 JPG 格式其实是同一个东西,在早期的 Windows 系统里,文件后缀名最多仅支持三个字符,于是就取 JPEG 的再简称 JPG 作为文件格式。当然最正式的后缀名是 JPEG,在后缀名上限放开之后,因为大家都已经习惯了 JPG 格式,自然也就很少人用其正式后缀名 JPEG 了。与此类似的例子还有安卓(Android,原官方中文名为安致)。

JPEG 采用有损压缩,但是压缩后文件体积远小于 PNG,并且在压缩的情况下,原图的视觉效果能很好地再现出来。对于颜色较多的图像,JPEG 对原图视效的保留是大幅优于 PNG 的。

有个不恰当的比喻——PNG 压缩是在文件二进制码处理上下功夫;而 JPEG 压缩则是在眼皮下耍把戏。专家组发现,人眼对亮度的敏感度要高于对颜色的敏感度:

(如图, 块和 块其实是同一种颜色)

因此 JPEG 在压缩上首先就抛除了 RGB 颜色表示法,转而使用以亮度、蓝色偏移、红色偏移三个参数表示色彩的 YCbCr 编码。既然人类对亮度的敏感程度高于色差,这就意味着我们可以将分量 Y 尽数保留,而在 Cb 和 Cr 分量上下功夫。

考虑一个 的颜色矩阵 。JPEG 压缩采取 滑动取样的技术,即生成一个 的滑动窗口,从矩阵的左上角每次处理四个值,每次将滑动窗口左上角的元素抽离出来并放入一个结果矩阵中。因此矩阵 将经历 轮处理,输出矩阵 。就实现了原图的体积压缩。注意到该过程仅在 Cb 和 Cr 通道上进行,分别压缩至原先的 ,总共压缩率就是 ,出图体积大概在原图的 左右。不难发现,我们的处理过程将部分元素略去了,故 JPEG 压缩为有损压缩

别急,这只是第一轮压缩。JPEG 在某些时候能够做到 的压缩率,这主要得益于 DCT 算法的加持。

DCT 全称 Discrete Cosine Transform 离散余弦变换(莫名想起傅大佬的变换来了),其精髓在于:一切信号均可用若干不同频率的标准余弦函数组合表出。这就好像把一个图像拆分成很多个初等函数的和。JPEG 的压缩用到八个标准余弦函数,分别是 ,频率顺次由低到高。

JPEG 会先将图像分成一个个 的区块(尺寸为经验值,效率普遍最优),在每个区块里按行按列分别进行 DCT,最后合并得到一个整个处理过的信号图谱。此时专家组又玩了一个把戏——他们发现人眼对高频的图像信号不敏感,因此在处理后的图像里,舍弃掉高频区块。既能保证视效的大致相同、也能达到大幅压缩体积的效果。

(随着频率采样总数的增加,DCT 的输出图像愈来愈接近原图,高频的添加并不会对图像产生多大影响)

此时对图像进行量化。这个过程的自定义程度是非常高的,这个过程需要量化表的参与,具体表现为用 DCT 处理后的图像矩阵的元素分别除以量化表矩阵相同位置的元素,并对商取整,得到量化后图像。一般地,量化表矩阵的元素越大,量化后图像的质量就越低。因为做整除法实质上是将对应通道的值控制在某个较小的值以内,当量化表的元素均趋近于正无穷时,量化后的结果将会是一个零矩阵 ,自然就是全损画质了。Photoshop 为 JPEG 格式的导出功能做了十二张量化表,分别对应不同的压缩质量。图像解码时,只需遍历乘以量化表矩阵的对应元素即可(注意并非矩阵乘法),由于除法取整的关系,量化也是一个有损压缩过程。

得到量化结果矩阵后,专家组用游程扫描法、兼以霍夫曼编码对矩阵进一步压缩,就可得到最终的压缩版 JPEG 图像了!

霍夫曼编码是一种根据关键字出现频率大小进行编码的算法,在压缩文件中极为常用,本质是将一个较长但是经常出现的串用一个短编码进行对应映射,可以省去大量空间;而游程扫描则是一种对矩阵元素进行遍历扫描、并将二维矩阵转为一维数组的方式,一般来说量化结果矩阵的右侧和下侧会出现多个 ,用游程扫描会将多次重复出现的零元素聚集到一块,方便霍夫曼算法的计算。

(游程扫描法遍历顺序)

至此便是整个 JPEG 格式的压缩过程。

总结

推荐一个免费不带广告且强大的在线图像压缩网站:Recompressor。该网站支持 PNG 和 JPEG 两种压缩方式。

随着图像解码技术的不断发展,以往那些用电脑看图,图片一行一行蜗速加载的时代已经一去不复返了。即便如此,网站搭建者仍会使用图片压缩技术来提升网站访问速度,以减少服务器性能的不必要消耗、并带给访客最佳的浏览体验。

在图像压缩方面,如果你的图像不包含透明像素点,且需保留的颜色、细节较多时,那么 JPEG 格式将是不二之选;如果你需要存放透明背景的图像,并且图像颜色较均匀,推荐 PNG 格式。

评论