GIF是图像交换格式(Graphics Interchange Format)的简称,它是由美国CompuServe公司在1987年所提出的图像文件格式,它最初的目的是希望每个BBS的使用者能够通过GIF图像 文件轻易存储并交换图像数据,这也就是它为什么被称为图像交换格式的原因了。
GIF文件格式采用了一种经过改进的LZW压缩算法,通常我们称 之为GIF-LZW算法。这是一种无损的压缩算法,压缩效率也比较高,并且GIF支持在一幅GIF文件中存放多幅彩色图像,并且可以按照一定的顺序和时间 间隔将多幅图像依次读出并显示在屏幕上,这样就可以形成一种简单的动画效果。尽管GIF最多只支持256色,但是由于它具有极佳的压缩效率并且可以做成动 画而早已被广泛接纳采用。下面笔者详细介绍GIF文件的格式。
GIF图像文件是以块的形式来存储图像信息,其中的块又称为区域结构。按照其中 块的特征又可以将所有的块分成三大类,分别是控制块(Control Block)、图像描述块(Graphic Rendering Block)和特殊用途块(Special Purpose Block)。控制块包含了控制数据流的处理以及硬件参数的设置,其成员主要包括文件头信息、逻辑屏幕描述块、图像控制扩充块和文件结尾块。图像描述块包 含了在显示设备上描述图像所需的信息,其成员包括图像描述块、全局调色板、局部调色板、图像压缩数据和图像说明扩充块。特殊用途块包含了与图像数据处理无 直接关系的信息,其成员包括图像注释扩充块和应用程序扩充块。下面详细介绍每一个块的详细结构。
1. 文件头信息
GIF的文件头只有六个字节,其结构定义如下:
typedef struct gifheader
{
BYTE bySignature[3];
BYTE byVersion[3];
} GIFHEADER;
其中,bySignature为GIF文件标示码,其固定值为“GIF”,使用者可以通过该域来判断一个图像文件是否是GIF图像格式的文件。 byVersion表明GIF文件的版本信息。其取值固定为“87a”和“89a”。分别表示GIF文件的版本为GIF87a或GIF89a。这两个版本 有一些不同,GIF87a公布的时间为1987年,该版本不支持动画和一些扩展属性。GIF89a是1989年确定的一个版本标准,只有89a版本才支持 动画、注释扩展和文本扩展。
2. 逻辑屏幕描述块
逻辑屏幕(Logical Screen)是一个虚拟屏幕(Virtual Screen),它相当于画布,所有的操作都是在它的基础上进行的,同时它也决定了图像的长度和宽度。逻辑屏幕描述块共占有七个字节,其具体结构定义如下:
typedef struct gifscrdesc
{
WORD wWidth;
WORD wDepth;
struct globalflag
{
BYTE PalBits : 3;
BYTE SortFlag : 1;
BYTE ColorRes : 3;
BYTE GlobalPal : 1;
} GlobalFlag;
BYTE byBackground;
BYTE byAspect;
} GIFSCRDESC;
其中,wWidth用来指定逻辑屏幕的宽度,wDepth用来指定逻辑屏幕的高度,glaobalflag为全域性数据,它的总长度为一个字节,其中前 三位(第0位到第2位)指定全局调色板的位数,可以通过该值来计算全局调色板的大小。第3位表明全局调色板中的RGB颜色值是否按照使用率进行从高到底的 次序排序的。第4到第6位指定图像的色彩分辨率。第7位指明GIF文件中是否具有全局调色板,其值取1表示有全局调色板,为0表示没有全局调色板。一个 GIF文件可以有全局调色板也可以没有全局调色板,如果定义了全局调色板并且没有定义某一幅图像的局部调色板,则本幅图像采用全局调色板;如果某一幅图像 定义的自己的局部调色板,则该幅图像使用自己的局部调色板。如果没有定义全局调色板,则GIF文件中的每一幅图像都必须定义自己的局部调色板。全局调色板 必须紧跟在逻辑屏幕描述块的后面,其大小由GlobalFlag.PalBits决定,其最大长度为768(3*256)字节。全局调色板的数据是按照 RGBRGB…..RGB的方式存储的。byBackground用来指定逻辑屏幕的背景颜色,也就相当于是画布的颜色。当图像长宽小于逻辑屏幕的大小 时,未被图像覆盖部分的颜色值由该值对应的全局调色板中的索引颜色值确定。如果没有全局调色板,该值无效,默认背景颜色为黑色。byAspect用来指定 逻辑屏幕的像素的长宽比例。
3. 图像描述块
一幅GIF图像文件中可以存储多幅图像,并且这些图像没有固定的存放次序。为了区分两幅 图像,GIF采用了一个字节的识别码(Image Separator)来判断下面的数据是否是图像描述块。图像描述块以0x2C开始,定义紧接着它的图像的性质,包括图像相对于逻辑屏幕边界的偏移量、图 像大小以及有无局部调色板和调色板的大小。图像描述块由10个字节组成:
typedef struct gifimage
{
WORD wLeft;
WORD wTop;
WORD wWidth;
WORD wDepth;
struct localflag
{
BYTE PalBits : 3;
BYTE Reserved : 2;
BYTE SortFlag : 1;
BYTE Interlace : 1;
BYTE LocalPal : 1;
} LocalFlag;
} GIFIMAGE;
其中,wLeft用来指定图像相对逻辑屏幕左上角的X坐标,以象素为单位。wTop用来指定图像相对逻辑屏幕左上角的Y坐标。wWdith和 wDepth分别用来指定图像的宽度和高度。LocalFlag用来指定区域性数据,也就是具体一幅图像的属性。LocalFlag的总长度为一个字节, 其中的前三位用来指定局部调色板的位数,可以根据该值来计算局部调色板的大小。第4位到第5位为保留位,没有使用,其值固定为0。第6位指明局部调色板中 的RGB颜色值是否经过排序,其值为1表示调色板中的RGB颜色值是按照其使用率从高到底的次序进行排序。第7位表示GIF图像是否以交错方式存储,其取 值为1表示以交错的方式进行存储。当图像是按照交错方式存储时,其图像数据的处理可以分为4个阶段:第一阶段从第0行开始,每次间隔8行进行处理;第二阶 段从第4行开始,每次间隔8行进行处理;第三阶段从第2行开始,每次间隔4行进行处理;第四阶段从第1行开始,每次间隔2行进行处理,这样当完成第一阶段 时就可以看到图像的概貌,当处理完第二阶段时,图像会变得清晰一些;当处理完第三阶段时,图像处理完成一半,清晰效果也进一步增强,当完成第四阶段,图像 处理完毕,显示出完整清晰的整幅图像。以交错方式存储是GIF文件格式的一个重要的特点,也是GIF文件格式的一个重要的优点。以交错方式存储的图像的好 处就是无需将整个图像文件解压完成就可以看到图像的概貌,这样可以减少用户的等待时间。第8位指明GIF图像是否含有局部调色板,如果含有局部调色板,则 局部调色板的内容应当紧跟在图像描述块的后面。
4. 图像压缩数据
图像压缩数据是按照GIF-LZW压缩编码后存储于图像压缩数据块 中的。GIF-LZW编码是一种经过改良的LZW编码方式,它是一种无损压缩的编码方法。GIF-LZW编码方法是将原始数据中的重复字符串建立一个字符 串表,然后用该重复字符串在字符串表中的索引来替代原始数据以达到压缩的目的。由于GIF-LZW压缩编码的需要,必须首先存储GIF-LZW的最小编码 长度以供解码程序使用,然后再存储编码后的图像数据。编码后的图像数据是一个个数据子块的方式存储的,每个数据子块的最大长度为256字节。数据子块的第 一个字节指定该数据子块的长度,接下来的数据为数据子块的内容。如果某个数据子块的第一个字节数值为0,即该数据子块中没有包含任何有用数据,则该子块称 为块终结符,用来标识数据子块到此结束。
5. 图像控制扩充块
图像控制扩充块是可选的,只应用于89a版本,它描述了与图像控制相关 的参数。一般情况下,图像控制扩充块位于一个图像块(包括图像标识符、局部颜色列表和图像数据)或文本扩展块的前面,用来控制跟在它后面的第一个图像(或 文本)的渲染(Render)形式,组成结构如下:
typedef struct gifcontrol
{
BYTE byBlockSize;
struct flag
{
BYTE Transparency : 1;
BYTE UserInput : 1;
BYTE DisposalMethod : 3;
BYTE Reserved : 3;
} Flag;
WORD wDelayTime;
BYTE byTransparencyIndex;
BYTE byTerminator;
} GIFCONTROL;
其中,byBlockSize用来指定该图像控制扩充块的长度,其取值固定为4。Flag用来描述图像控制相关数据,它的长度为1个字节。它的第0位用 来指定图像中是否具有透明性的颜色,如果该位为1,这表明图像中某种颜色具有透明性,该颜色由参数byTransparencyIndex指定。第一位用 来判断在显示一幅图像后,是否需要用户输入后再进行下一个动作。如果该位为1,则表示应用程序在进行下一个动作之前需要用户输入。第2-4位用来指定图像 显示后的处理方式,当该值为0时,表示没有指定任何处理方式;当该值为1时,表明不进行任何处理动作;当该值为2时,表明图像显示后以背景色擦去;当该值 为3时,表明图像显示后恢复原先的背景图像。第5-7位为保留位,没有任何含义,固定为0。wDelayTime用来指定应用程序进行下一步操作之前延迟 的时间,单位为0.01秒。如果Flag.UserInput和wDelayTime都设定了,则以先发者为主,如果没有到指定的延迟时间即有用户输入, 则应用程序直接进行下一步操作。如果到达延迟时间后还没有用户输入,应用程序也直接进入下一步操作。byTransparenceIndex用来指定图像 中透明色的颜色索引,指定的透明色将不在显示设备上显示。byTerminator为块终结符,其值固定为0。
6. 图像说明扩充块
图像说明扩充块又可以称为图像文本扩展块,它用来绘制一个简单的文本图像,这一部分由用来绘制的纯文本数据(7位的 ASCII字符)和控制绘制的参数等组成。绘制文本借助于一个文本框(Text Grid)来定义边界,在文本框中划分多个单元格,每个字符占用一个单元,绘制时按从左到右、从上到下的顺序依次进行,直到最后一个字符或者占满整个文本 框(之后的字符将被忽略,因此定义文本框的大小时应该注意到是否可以容纳整个文本),绘制文本的颜色使用全局颜色列表,没有则可以使用一个已经保存的前一 个颜色列表。另外,图形文本扩展块也属于图形块(Graphic Rendering Block),可以在它前面定义图形控制扩展对它的表现形式进一步修改。图像说明扩充块的组成:
typedef struct gifplaintext
{
BYTE byBlockSize;
WORD wTextGridLeft;
WORD wTextGridTop;
WORD wTextGridWidth;
WORD wTextGridDepth;
BYTE byCharCellWidth;
BYTE byCharCellDepth;
BYTE byForeColorIndex;
BYTE byBackColorIndex;
} GIFPLAINTEXT;
其中,byBlockSize用来指定该图像扩充块的长度,其取值固定为13。wTextGridLeft用来指定文字显示方格相对于逻辑屏幕左上角的 X坐标(以像素为单位)。wTextGridTop用来指定文字显示方格相对于逻辑屏幕左上角的Y坐标。wTextGridWidth用来指定文字显示方 格的宽度。wTextGridDepth用来指定文字显示方格的高度。byCharCellWidth用来指定字符的宽度, byCharCellDepth用来指定字符的高度。byForeColorIndex用来指定字符的前景色,byBackColorIndex用来指定 字符的背景色。
7. 图像注释扩充块
图像注释扩充块包含了图像的文字注释说明,可以用来记录图形、版权、描述等任何的非图形和控制的 纯文本数据(7位的ASCII字符),注释扩展并不影响对图象数据流的处理,解码器完全可以忽略它。存放位置可以是数据流的任何地方,最好不要妨碍控制和 数据块,推荐放在数据流的开始或结尾。在GIF中用识别码0xFE来判断一个扩充块是否为图像注释扩充块。图像注释扩充块中的数据子块个数不限,必须通过 块终结符来判断该扩充块是否结束。
8. 应用程序扩充块
应用程序扩充块包含了制作该GIF图像文件的应用程序的信息,GIF中用识别码0xFF来判断一个扩充块是否为应用程序扩充块。它的结构定义如下:
typedef struct gifapplication
{
BYTE byBlockSize;
BYTE byIdentifier[8];
BYTE byAuthentication[3];
} GIFAPPLICATION;
其中,byBlockSize用来指定该应用程序扩充块的长度,其取值固定为12。byIdentifier用来指定应用程序名称。byAuthentication用来指定应用程序的识别码。
9. 文件结尾块
文件结尾块为GIF图像文件的最后一个字节,其取值固定为0x3B。