出错:前端大全 - 微信公众号
作者:airuikun
问题:png 的图片经常使用,但 png 到底是什么,它的压缩原理是什么?
1. 什么是 PNG
PNG的全称叫便携式网络图型(Portable Network Graphics)是目前最流行的网络传输和展示的图片格式,原因有如下几点:
[1] - 无损压缩:
PNG图片采取了基于LZ77派生算法对文件进行压缩,使得它压缩比率更高,生成的文件体积更小,并且不损失数据.
[2] - 体积小:
它利用特殊的编码方法标记重复出现的数据,使得同样格式的图片,PNG图片文件的体积更小. 网络通讯中因受带宽制约,在保证图片清晰、逼真的前提下,优先选择PNG格式的图片.
[3] - 支持透明效果:
PNG支持对原图像定义256个透明层次,使得图像的边缘能与任何背景平滑融合,这种功能是GIF和JPEG没有的.
2. PNG类型
PNG 图片主要有三个类型,分别为 PNG 8、PNG 24、PNG 32.
[1] - PNG8:
PNG8中的 8,指的是8bits,相当于用 2^8 (2的8次方)大小来存储一张图片的颜色种类,2^8 等于256,也就是说PNG8 能存储256种颜色,一张图片如果颜色种类很少,将它设置成PNG8 的图片类型是非常适合的.
[2] - PNG24:
PNG24中的24,相当于3乘以 8 等于 24,就是用三个8bits分别去表示 R(红)、G(绿)、B(蓝). R(0 ~ 255), G(0 ~ 255), B(0 ~ 255),可以表达256乘以256乘以256=16777216种颜色的图片,这样PNG 24就能比PNG 8表示色彩更丰富的图片. 但是所占用的空间相对就更大了. 但,其不支持透明.
[3] - PNG32:
PNG32中的32,相当于PNG 24 加上 8bits 的透明颜色通道,就相当于R(红)、G(绿)、B(蓝)、A(透明). R(0 ~ 255), G(0 ~ 255), B(0 ~ 255),A(0 ~ 255). 比 PNG24多了一个A(透明),也就是说PNG 32能表示跟PNG 24一样多的色彩,并且还支持256种透明的颜色,能表示更加丰富的图片颜色类型.
应当根据图片来选择正确的格式,在能表示图片中颜色的前提下,尽量选择位数较少的 PNG 格式.
3. PNG图片数据结构
PNG图片的数据结构其实跟 http 请求的结构很像,都是一个数据头,后面跟着很多的数据块,如下图所示:
PNG8 由一个 8 字节的 PNG 文件署名域和按照特定结构组织的 3 个以上的数据块组成,其中数据块分成两种,关键数据块和可选数据块,关键数块为如下四种:
- 文件头数据块
- 调色板数据块
- 图像数据块
- 图像结束数据块
而每个数据块由以下四个数据域组成:
- 长度
- 数据块类型码
- 数据块数据
- 循环冗余校验
如果用 vim 的查看编码模式打开一张png图片,会是下面这个样子:
第一眼看到这一坨坨十六进制编码是不是感觉晦涩难懂?
这一堆十六进制编码的含义:
8950 4e47 0d0a 1a0a:这个是 PNG图片的头,所有的PNG图片的头都是这一串编码,图片软件通过这串编码判定这个文件是不是PNG格式的图片.
0000 000d:是iHDR数据块的长度,为13.
4948 4452:是数据块的 type,为 IHDR,之后紧跟着是data.
0000 02bc:是图片的宽度.
0000 03a5:是高度.
以此类推,每一段十六进制编码就代表着一个特定的含义. 其他的就不一一分析了.
参考:
4. 什么样的PNG图片更适合压缩
常规的png图片,颜色越单一,颜色值越少,压缩率就越大,比如下面这张图:
它仅仅由红色和绿色构成,如果用0代表红色,用1代表绿色,那用数字表示这张图就是下面这个样子:
00000000000000000
00000000000000000
00000000000000000
1111111111111111111111111
1111111111111111111111111
1111111111111111111111111
可以看到,这张图片是用了大量重复的数字,可以将重复的数字去掉,直接用数组形式的[0, 1]就可以直接表示出这张图片了,仅仅用两个数字,就能表示出一张很大的图片,这样就极大的压缩了一张png图片.
所以,颜色越单一,颜色值越少,颜色差异越小的png图片,压缩率就越大,体积就越小.
5. PNG的压缩
PNG图片的压缩,分两个阶段:
[1] - 预解析(Prediction):这个阶段就是对png图片进行一个预处理,处理后让它更方便后续的压缩.
[2] - 压缩(Compression):执行Deflate压缩,该算法结合了 LZ77 算法和 Huffman 算法对图片进行编码.
5.1. 预解析(Prediction)
png图片用差分编码(Delta encoding)对图片进行预处理,处理每一个的像素点中每条通道的值,差分编码主要有几种:
- 不过滤
- X-A
- X-B
- X-(A+B)/2(又称平均值)
- Paeth推断(这种比较复杂)
假设,一张png图片如下:
这张图片是一个红色逐渐增强的渐变色图,它的红色从左到右逐渐加强,映射成数组的值为[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]
最后的[1,1,1,1,1,1,1]这个结果出现了大量的重复数字,这样就非常适合进行压缩.
这就是为什么渐变色图片、颜色值变化不大并且颜色单一的图片更容易压缩的原理.
差分编码的目的,就是尽可能的将png图片数据值转换成一组重复的、低的值,这样的值更容易被压缩.
最后还要注意的是,差分编码处理的是每一个的像素点中每条颜色通道的值,R(红)、G(绿)、B(蓝)、A(透明)四个颜色通道的值分别进行处理.
5.2. 压缩(Compression)
压缩阶段会将预处理阶段得到的结果进行Deflate压缩,它由 Huffman 编码 和 LZ77压缩构成.
如前面所说,Deflate压缩会标记图片所有的重复数据,并记录数据特征和结构,会得到一个压缩比最大的 png图片编码数据.
Deflate是一种压缩数据流的算法. 任何需要流式压缩的地方都可以用.
还有就是前面说过,一个png图片,是由很多的数据块构成的,但是数据块里面的一些信息其实是没有用的,比如用Photoshop保存了一张png图片,图片里就会有一个区块记录“这张图片是由photshop 创建的”,很多类似这些信息都是无用的,如果用photoshop的“导出web格式”就能去掉这些无用信息. 导出web格式前后对比效果如下图所示:
可以看到,导出web格式,去除了很多无用信息后,图片明显小了很多.
6. 结语
PNG有很多优点,并且应用广泛,但是还是需要根据具体的场景来选用:
[1] - 如果原始的图片为高清的,但是不要求进行无损的压缩,那么可以选择类似于 JPG 这样的有损压缩.
[2] - 但是从反方面来说,如果原始图片较为简单,并且需要支持透明形式,那么 PNG 要优于 JPG.
参考
[1] - 图片压缩知识梳理(1) - PNG 原理 - 2017.04.22
[2] - PNG、JPEG、BMP等几种图片格式详解(一)—— PNG - 2017.09.06