GIF 格式及LZW算法浅析

Posted on Sep 20, 2012

前段时间得知一个产品需求,需要在Flash Player中显示gif动画图片。虽然Flash支持gif图像的载入,但无法播放动画。

花了不少时间去了解GIF格式,虽然顺利解决了问题,但是知其然也知其所以然,了解了这些知识,对理解编码/解码的过程和解决问题有非常大的帮助。

gif sample

GIF概述

Graphics Interchange Format(GIF,图形交换格式)是一种位图的图形文件格式,以8位色(即256种颜色)重现真彩色的图像。它实际上是一种压缩文档,采用LZW压缩算法进行编码,有效地减少了图像文件在网络上传输的时间。是目前广泛应用于网络传输的图像格式之一。

GIF主要分为两个版本,即GIF 87a和GIF 89a:

GIF 87a:是在1987年制定的版本; GIF 89a:是在1989年制定的版本。在这个版本中,为GIF文档扩充了图形控制区块、备注、说明、应用程序接口等四个区块,并提供了对透明色和多帧动画的支持。

GIF格式结构

GIF文件由文件头,描述块,彩色表,数据块,扩展块和结束符构成,GIF87a和GIF89a的区别在于:后者较前者增加了扩展块,从功能上看即提供了对透明色和多帧动画的支持。

结构组成

结构如下表所示:

Header Header Header
Logical Screen Descriptor Screen Descriptor Block GIF Data Stream
Global Color Table Global Color Table(optional)
Application Extension Extension Blocks(optional, repeated)
Graphic Control Extension*
Image Descriptor Image Blocks(repeated)
Local Color Table
Table Based Image Data
Extension Blocks(optional, repeated)
Trailer Trailer Trailer

常见版本结构如下:

GIF87a:

Header Header
Logical Screen Descriptor Screen Descriptor Block
Global Color Table Global Color Table(optional)
Image Descriptor Image Blocks
Local Color Table
Table Based Image Data
Trailer Trailer

GIF89a :

Header Header
Header Header
Logical Screen Descriptor Screen Descriptor Block
Global Color Table Global Color Table(optional)
Application Extension Extension Blocks(optional, repeated)
Graphic Control Extension*
Image Descriptor Image Blocks(repeated)
Local Color Table
Table Based Image Data
Extension Blocks(optional, repeated)
Trailer Trailer
Logical Screen Descriptor Screen Descriptor Block
Global Color Table Global Color Table(optional)
Image Descriptor Image Blocks
Local Color Table
Table Based Image Data
Trailer Trailer

*: 如果为多帧图像,则必须要Graphic Control Extension.

结构说明

Header:描述GIF Signature和 Version; Logical Screen Descriptor:包含定义图像显示区域的参数,包括背景颜色信息; Global Color Table:GIF图像是基于颜色表的,存储的数据是该点的颜色对应于颜色表的索引值。全局颜色表作用域为整个数据流,可以用于那些没有局部颜色表的图像。 Image Descriptor:定义图像的属性,包括图像相对于逻辑屏幕边界的偏移量、图像大小以及有无局部颜色列表和颜色列表大小; Local Color Table:和Global的一样,都是可选的颜色表; Table Based Image Data:GIF使用LZW压缩算法,包含LZW编码长度(LZW Minimum Code Size)和图像数据(Image Data)两部分。 Graphic Control Extension:控制跟在它后面的第一个图像(或文本)的渲染方式; Comment Extension:用来说明图形、作者或者其他任何非图形数据和控制信息的文本信息; Plain Text Extension:包含文本数据和描绘文本所需的参数 Application Extension:包含制作该图像文件的应用程序的相关信息; Trailer:表示GIF文件的结尾,它包含一个固定的数值:0x3B。 各部分的数据结构及编码细则可参考 GIF89a Specification,不再赘述。

LZW压缩算法

GIF采用的LZW(Lempel-Ziv-Welch)压缩算法,这是一种基于字典的无损数据压缩算法。1978年Abraham Lempel与Jacob Ziv在发布了LZ78 压缩算法, Terry Welchy 以此作为基础,1984年发布其改进版本—— LZW。

算法说明

LZW压缩算法的基本思想是建立一个编码表(字典),将输入字符串映射成定长的码字输出,通常码长设为12bit。把数字图像当作一个一维的比特串,算法在产生输出串的同时动态地更新编码表,这样码表与串表对应产生压缩图像的特殊性质。串表是动态产生的,编码前先初始化,使其包含所有的单字符串。压缩过程中,串表中不断产生新字符串(串表中没有的字符串),存储新字符串时也保存与新串的前缀相应的子码。

简单地讲,编码过程如下:

  1. 初始化字典,包含字符串中所有的单个字符;
  2. 在当前读到的位置,从字典里找到能够匹配的最长字符串ω;
  3. 返回ω在字典中的索引值,替代ω;
  4. 把ω+其后一个字符组成一个新的字符串,添加到字典中;
  5. 回到第2步 。

算法示例

下面借助Wikipedia的示例有助于理解,实际编码规则并非如此:

有这么一段字符串

TOBEORNOTTOBEORTOBEORNOT#

#假定为LZW的结束符,因此字符编码表中需要包含A-Z 和 # 27个项;当字典扩展时,需要增加码字(Code Word)位宽以满足不断增加的新表项 (前缀,Prefix)。25=32,5bit就够存储初始编码表所有数据流。如果码字位宽,每次加1位。初始编码表如下:

Symbol Binary Decimal
# 00000 0
A 00001 1
B 00010 2
C 00011 3
D 00100 4
E 00101 5
F 00110 6
G 00111 7
H 01000 8
I 01001 9
J 01010 10
K 01011 11
L 01100 12
M 01101 13
N 01110 14
O 01111 15
P 10000 16
Q 10001 17
R 10010 18
S 10011 19
T 10100 20
U 10101 21
V 10110 22
W 10111 23
X 11000 24
Y 11001 25
Z 11010 26

编码

Current Sequence Next Char Output Extended Dictionary Comments
Code Bits
NULL T
T O 20 10100 27: TO 27 = first available code after 0 through 26
O B 15 01111 28: OB
B E 2 00010 29: BE
E O 5 00101 30: EO
O R 15 01111 31: OR
R N 18 10010 32: RN 32 requires 6 bits, so for next output use 6 bits
N O 14 001110 33: NO
O T 15 001111 34: OT
T T 20 010100 35: TT
TO B 27 011011 36: TOB
BE O 29 011101 37: BEO
OR T 31 011111 38: ORT
TOB E 36 100100 39: TOBE
EO R 30 011110 40: EOR
RN O 32 100000 41: RNO
OT # 34 100010 # stops the algorithm; send the cur seq
0 000000 and the stop code

编码前长度 : 25 symbols × 5 bits/symbol = 125 bits

编码后长度:(6 codes × 5 bits/code) + (11 codes × 6 bits/code) = 96 bits

使用LZW节省了29 bits, 差不多减少了 22%的数据量,效果明显。

解码

Input Output Sequence New Dictionary Entry Comments
Bits Code Full Conjecture
10100 20 T 27: T?
01111 15 O 27: TO 28: O?
00010 2 B 28: OB 29: B?
00101 5 E 29: BE 30: E?
01111 15 O 30: EO 31: O?
10010 18 R 31: OR 32: R? created code 31 (last to fit in 5 bits)
001110 14 N 32: RN 33: N? so start reading input at 6 bits
001111 15 O 33: NO 34: O?
010100 20 T 34: OT 35: T?
011011 27 TO 35: TT 36: TO?
011101 29 BE 36: TOB 37: BE? 36 = TO + 1st symbol (B) of
011111 31 OR 37: BEO 38: OR? next coded sequence received (BE)
100100 36 TOB 38: ORT 39: TOB?
011110 30 EO 39: TOBE 40: EO?
100000 32 RN 40: EOR 41: RN?
100010 34 OT 41: RNO 42: OT?
000000 0 #

总结

简单介绍了GIF文件格式的特点及其内部的结构,并浅析了LZW压缩算法的原理,通过简单的例子演示了LZW编码/解码的过程。相比GIF 87a,GIF 89a增加了很实用的两项功能:透明色支持和多帧动画,也正是因此GIF才会在Internet上如此受欢迎。虽然遭遇了专利风波,但也因此催生了PNG格式,如今LZW的专利都过期了,GIF依然流行。 😉

阅读延伸

GIF89a Specification(W3C) LZMA(Wikipedia)


参考资料

  1. Graphics Interchange Format(Wikipedia)
  2. GIF89a Specification
  3. The Structure of a GIF89a file
  4. GIF format
  5. http://www.cnblogs.com/KevinXer1129/archive/2008/10/09/1307251.html
  6. http://www.chinaai.org/ip/image-processing/gif-struct.html
  7. LZW(Wikipedia)
  8. http://www.chinaai.org/ip/image-processing/lzw-gif.html
  9. Terry Welch, “A Technique for High-Performance Data Compression”, IEEE Computer, June 1984, p. 8–19