在我们日常工作中,天天都在用,并且在网路传输和图片展示中,是一个很主流的格式,今天这片文章,就用PNG,来作为主角,来探究一下,图片压缩中的一些知识;
PNG
- 体积小:传输同样的图片,png就比别人要小
- 支持透明:这个是 gif 和 jpeg 没有的功能
PNG的数据结构
是不是和HTTP请求的结构很像,一个Head,然后一堆Chunk,这个就是PNG的数据结构;
如果你用 vim 打开一张 png
## step1.打开一个png
vi -b xxx.png
## step2.使用十六进制显示
:%!xxd
8950 4e47 0d0a 1a0a:这个是PNG图片的头,所有的PNG图片的头都是这一串编码。
0000 000d:是iHDR数据块的长度,为13。
4948 4452:是数据块的type,为IHDR,之后紧跟着是data。
0000 00c8:是图片的宽度,转换一下是200。
0000 00c8:是图片的高度,转换一下是200
png 是如何做压缩的?
压缩分为两个阶段:
解析 + 压缩,PNG都有自己特殊的处理;
解析阶段(特殊的编码方式)
在压缩之前,有一个步骤,叫做解析(Prediction),处理之后,更加方便后面的压缩,类似化妆前,先打粉底、涂乳液、摸精华先上去;
PNG用差分编码(Delta encoding)对图片进行一个预先处理,处理每一个像素点中的每一条通道的值,R(红)、G(绿)、B(蓝)、A(透明);
查分编码主要有几种:
- 不过滤
- X-A
- X-B
- X-(A+B)/2(又称平均值)
- Paeth 推断
这张图片是一个红色逐渐增强的渐变色图,它的红色从左到右逐渐加强,映射成数组的值为[1,2,3,4,5,6,7,8]。
使用X-A的差分编码的话,那就是: [2-1=1, 3-2=1, 4-3=1, 5-4=1, 6-5=1, 7-6=1, 8-7=1],得到的结果为[1,1,1,1,1,1,1],这个结果出现了大量的重复数字,这样就非常适合进行压缩。
差分编码的目的,就是尽可能的将png数据值转换成一组重复的、低的值,这样的值更容易被压缩。最后还要注意的是,差分编码处理的是每一个的像素点中每条颜色通道的值,R(红)、G(绿)、B(蓝)、A(透明)四个颜色通道的值分别进行处理。
压缩阶段(删除图片信息)
压缩阶段会将预处理阶段得到的结果进行Deflate压缩, 这种压缩算法,会标记图片所有的重复数据,并记录数据特征和结构,会得到一个压缩比最大的png图片编码数据。
前面我们知道了PNG的数据结构,一个 NG图片是由很多的数据块构成的,但是并不是所有的都是必须的,一些设备信息,光圈信息,拍摄日期,定位信息都是可以直接丢掉的;
说一个最实际的场景,用 Photoshop 保存了一张PNG都会很大,因为 Adobe 会在 PNG 里面存储很多信息,设计师的需要这些信息,前端是不需要的,如果用Photoshop 的 “导出web格式” 就能去掉这些无用信息。所以体积一下就小了,可以自己试试;
什么样的图片压缩效果好?
颜色越单一,颜色值越少,颜色差异越小的PNG,压缩率就越大,体积就越小,压缩率就越高,这就是为什么渐变色图片、颜色值变化不大、颜色单一的图片更容易压缩呢?
它仅仅由红色和绿色构成,如果用0代表红色,用1代表绿色,那用数字表示这张图就是下面这个样子:
00000000000000000
00000000000000000
00000000000000000
1111111111111111111111111
1111111111111111111111111
1111111111111111111111111
这张图片是用了大量重复的数字,我们可以将重复的数字去掉,直接用数组形式的[0, 1]就可以直接表示出这张图片了,仅仅用两个数字,就能表示出一张很大的图片,这样就极大的压缩了一张 PNG。