原文:PNG 图片压缩原理解析 - 2019.04.01

出错:前端大全 - 微信公众号

作者:airuikun

https://github.com/airuikun/blog/issues/1

问题: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:是高度.

以此类推,每一段十六进制编码就代表着一个特定的含义. 其他的就不一一分析了.

参考:

PNG文件结构分析 ---Png解析 - 2014.04.30

一步一步解码 PNG 图片 - 2019.12.07

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

[3] - 一步一步解码 PNG 图片 - 2019.12.07

[4] - PNG文件结构分析 ---Png解析 - 2014.04.30

Last modification:November 2nd, 2020 at 02:25 pm