图形学 | 格物致知!PNG 除了无损压缩你还知道什么?

5,236 阅读9分钟

点赞关注,不再迷路,你的支持对我意义重大!

🔥 Hi,我是丑丑。本文 GitHub · Android-NoteBook 已收录,这里有 Android 进阶成长路线笔记 & 博客,欢迎跟着彭丑丑一起成长。(联系方式在 GitHub)

前言

  • PNG(Protable Network Graphics,便携式网络图形) 是一种非常常见的图片格式,深入理解 PNG 文件原理,有利于加强对图片编解码过程的理解,便于开展优化工作。
  • 在这篇文章里,我将带你探究 PNG 图片的 数据结构 & 编码原理 & 优化方法等。如果能帮上忙,请务必点赞加关注,这真的对我非常重要。

系列文章


目录


1. 概述

1.1 定义

PNG(Portable Network Graphics,便携式网络图形)是一种 无损压缩的位图图形格式。它本身的设计目的是替代 GIF 格式,所以它与 GIF 有一些相似之处。

1.1 特点

  • 无损压缩(Lossless Compression):采用了 LZ77 派生算法 + Huffman 编码,压缩率更高,体积更小且不损失数据;

  • 支持透明:支持 8 位透明通道,而 GIF 只支持 1 比特透明通道,JPEG 不支持透明通道;

  • 图像的复杂程度越低,使用 PNG 格式的压缩率更高(原因见 第 3 节 编码原理);

  • 支持五种像素 / 颜色类型

    • 索引色(Indexed-colour,8 位)
    • 灰度(Greyscale,8 位)
    • 真彩色(Truecolour,24 位)
    • 灰度透明(Greyscale with alpha,16 位)
    • 真彩色透明(Truecolour with alpha,32 位)

引用自 www.w3.org/TR/2003/REC… —— w3.org

提示: 网上所述三种 PNG 类型为:PNG 8、PNG 24、PNG 32,经查阅百科、PNG 官网和《PNG 文件协议》未能找到支撑依据,本文不作阐述。


2. PNG 数据结构

这一节我们来讨论 PNG 图片的数据结构,一个 PNG 格式文件(或数据流)由一个 8 字节的签名和若干个数据块(chunk)组成。

2.1 PNG 签名

PNG 文件头部的 8 字节为文件签名(或称魔数),这个值将被用来识别文件是否为 PNG 文件,数据固定为8950 4E47 0D0A 1A0A。以下是我任意打开的一个 PNG 文件:

提示: 使用 010 Editor 可以查看文件二进制数据。首次打开 PNG 文件时,它会提示安装 PNG.bt,安装后将帮助解析你读懂每块数据的含义。

2.2 数据块

  • 数据块类型

PNG 定义了两种数据块:关键数据块(critical chunks)& 辅助数据块(ancillary chunks)

其中,关键数据块是从 PNG 数据流中成功解码图像所必需的,而辅助数据块是可选的,我们将重点了解关键数据块。关键数据块分为四种:文件头数据块、调色板数据块、图像数据块和图像结束数据块。

  • 数据块的内部结构

PNG 的每一块数据块都由四个部分组成:

名称字节数描述
长度(length)4指定数据块中数据域的长度
数据块类型码(Chunk Type Code)4由(A-Z、a-z)组成
数据length数据块数据
循环冗余检测(CRC)4用于检错
  • 文件头数据块 IDHR(header chunk)

文件头数据块是 PNG 文件中的第一个数据块,包含了 PNG 文件的基本信息,由 13 个字节组成,数据结构如下:

字段字节数描述
图片宽度(Width)4以像素为单位
图片高度(Height)4以像素为单位
图像深度(Bit depth)1/
颜色类型(ColorType)15 种颜色类型:
索引色
灰度
灰度透明
真彩色(24 位直接色)
真彩色透明(32 位直接色)
压缩方法(Compression method)1LZ77 派生算法
滤波方法(Filter method)1/
隔行扫描方法(Interface method)10:非隔行扫描
1: Adam7(7遍隔行扫描方法)
  • 调色板数据块 PLTE(palette chunk)

调色板数据块包含有与索引彩色图像(indexed-color image)相关的彩色变换数据,它仅与索引彩色图像有关,而且要放在图像数据块 IDAT 之前。真彩色的 PNG 数据流也可以有调色板数据块,目的是便于非真彩色显示程序用它来量化图像数据,从而显示该图像。

  • 图像数据块 IDAT(image data chunk)

图像数据块是图像实际存储的数据,可包含多个连续顺序的图像数据块。

  • 图像结束数据块 IEND(image trailer chunk)

图像结束数据块标记 PNG 文件或者数据流已经结束,必须要放在尾部。


3. PNG 编码原理

通过查阅《Protable Network Graphic (PNG) Specification (Second Edition)》,可以了解到 PNG 文件的编码过程主要分为五个阶段:

  • 1、通过提取(pass extraction)
  • 2、扫描线序列化(scanline serialization)
  • 3、过滤(filtering)
  • 4、压缩(compression)
  • 5、分块(chunking)

前两个步骤我看不懂,我直接讲后三个步骤。

3.3 滤波(filtering)

这个步骤的主要思想是 增量编码,即:一个值可以表示为与前值的差值。

例如:[2,3,4,5,6,7,8][2,3,4,5,6,7,8]可以编码为[2,32=1,43=1,54=1,65=1,76=1,87=1][2,3-2=1,4-3=1,5-4=1,6-5=1,7-6=1,8-7=1] =>[2,1,1,1,1,1,1][2,1,1,1,1,1,1]

可以发现,增量编码后的数据变成了大量重复、低值的数据,这样的数据是有利于压缩的,原因我在 第 3.4 节 说。

回到 PNG 的滤波步骤,这个步骤主要是选择合适的差分过滤器,分别处理每一行中的每个像素,使得差分编码的数值尽可能重复、尽可能小,要点如下:

  • 1、滤波器有以下五种

引用自 zh.wikipedia.org/wiki/PNG —— 维基百科

在后面的 分块(chunking) 步骤中,会把编码过程中使用的滤波方法被记录 IHDR 中的Filter method字段里。

  • 2、为了最优效果,每一行可使用不同滤波器

引用自 medium.com/@duhroach/h… —— Colt McAnlis 著

  • 3、滤波却是按通道而不是按像素进行的

滤波是按通道而不是按像素进行的,也就是说滤波是先扫描一行中像素的红色通道,然后再扫描一行中像素的蓝色通道,以此类推。

  • 4、一行中所有通道使用相同的滤波器

3.4 压缩(compression)

PNG 的压缩过程结合了 LZ77 编码和 Huffman 编码,要点如下:

  • 1、压缩过程是无损压缩
  • 2、颜色越单一,颜色差异越小,压缩率越大

LZ77 编码

一种基于字典的、“滑动窗”的无损压缩算法。

Huffman 编码(霍夫曼编码)

一种用于无损压缩的变长编码,主要思想为:评估码元的出现几率选择不同长度的编码,几率较高的码元使用较短的编码,而几率较低的码元使用较长的编码,这将使得编码的平均长度降低。

3.5 分块(chunking)

分块可方便地将压缩数据流分解为可管理的块,关于数据块的结构我们在 第 2 节中讨论过。


4. 缩小 PNG 文件大小

4.1 减少颜色数量 & 差异

第 3 节 编码原理 的讨论,我们提到了 增量编码 的概念,通过减少颜色的数量 & 差异,滤波步骤之后数据的差异更小,有利于在压缩步骤中缩小文件。

不过,减少颜色的数量 & 差异等同于给图片进行了有损编码,应当确保在高效压缩和图片质量之间保持适当的平衡。

4.2 采用索引色格式

如果图片的单色数量不超过 256 个,则可以采用Indexed-colour(索引色)格式。原始图像的每个像素由调色板中的一个索引表示。此时,每个像素的字节数由 3 字节(无透明通道)和 4 字节(有透明通道)减少到 1 字节,大大缩小文件。

引用自 developer.android.com/topic/perfo… —— Android Developers

4.3 采用矢量量化(vector quantization)

如果图片的单色数量超过 256 个,就需要 采用矢量量化较少颜色数量,再生成索引色格式。矢量量化就是将颜色相似的一块区域合并为同一种颜色的舍入的过程,主要分为以下步骤:

  • 1、根据相近区域相似度进行分组;
  • 2、将该组中所有颜色替换为单个中心点的颜色;
  • 3、生成索引色格式。

引用自 developer.android.com/topic/perfo… —— Android Developers


5. PNG 的有损压缩方案

第 3 节 编码原理 中我们提到了 PNG 压缩是无损压缩,为了进一步提高压缩率,可以采用有损压缩算法,以下是现有的 PNG 有损压缩方案。

在官网介绍中,其实可以清楚地了解到它们的原理,主要就是采用了 第 4.3 节 讨论的方案:采用矢量量化较少颜色数量,再生成索引色格式。

5.1 TinyPNG

官方地址:tinypng.com

How does it work?

...... This technique is called “quantization”. By reducing the number of colors, 24-bit PNG files can be converted to much smaller 8-bit indexed color images. All unnecessary metadata is stripped too. The result better PNG files with 100% support for transparency. Have your cake and eat it too!

局限:只提供了 HTTP 请求的方式,并且有次数限制。

5.2 pngquant

官方地址:pngquant.org

Features

High-quality palette generation using a combination of vector quantization algorithms. ......

5.3 zopflipng

5.4 pngcursh

Editting...


参考资料

推荐阅读

感谢喜欢!你的点赞是对我最大的鼓励!欢迎关注彭旭锐的GitHub!