GIF图片介绍和LZW算法说明
1. GIF格式
GIF图像的文件格式如下:
重点字段介绍:
逻辑屏幕标志符:包含了逻辑屏幕的长宽,是否包含全局颜色列表,背景色等。
全局颜色列表:包含了图片中使用的所有颜色,而图片的数据使用全局颜色列表中的索引代替。
图像块:gif的数据是由数据块组成,每个数据块的长度最大为255
2. LZW算法
全称为“串表压缩算法”,LZW代表了研发该算法的三个人(坑爹啊,还以为是英文缩写)。属于字典编码的一种,最大的优点在于压缩后的数据不需要额外携带字典就可以解压。GIF采用LZW算法进行编码的。
2.1 首先介绍几个相关术语:
数据流:需要进行编码的数据串,GIF中指像素的颜色值。LZW编码时的输入
编码流:数据流编码的结果。LZW编码时的输出
编译表:编码时候的字典表,是动态建立的。
字符:数据流中最基本的单位,GIF中一个像素的颜色在颜色列表中的序号。
字符串:由连续字符组成的,前缀和后缀一起代表了字符串
前缀:也是字符串,但可以为空。具体解释见下文
后缀:也是字符串,一个字符就是后缀,可以为空。具体解释见下文
2.2 编码流程
首先举一个简单的例子,有一个数据流为:abcbabbac
我们为了和数据流的字符进行区别,我们采用1,2,3这样的数字进行编码。数据流中可能出现的字符为,a~z,所以我们初始化编译表,用1~26,代表a~z单个字符。所以对于其它的字符串只能从27进行编码。初始化前缀为空,后缀也为空,编码流为空,编译表为1~26和a~z的对应。
1.2.1 从数据流取字符a作为后缀,前缀为空,字符串为a,在编译表中存在,为1,字符串变前缀。前缀:a;后缀:空;字符串:a;编码流:空;编译表:单个字符的对应(后面不再显示)
1.2.2 取字符b作为后缀,字符串为:ab,编译表中不存在,定义ab为27,前缀输出,后缀变前缀。前缀:b;后缀:空;字符串:b;编码流:1;编译表:27=ab
1.2.3 取字符c作为后缀,字符串为:bc,编译表不存在,定义bc为28,前缀输出,后缀变前缀。前缀:c;后缀:空;字符串:c;编码流:1-2;编译表:27=ab 28=bc
1.2.4 取字符b作为后缀,字符串为:cb,编译表不存在,定义cb为29,前缀输出,后缀变前缀。前缀:b;后缀:空;字符串:b;编码流:1-2-3;编译表:27=ab 28=bc 29=cb
1.2.5 取字符a作为后缀,字符串为:ba,编译表不存在,定义ba为30,前缀输出,后缀变前缀。前缀:a;后缀:空;字符串:a;编码流:1-2-3-2;编译表:27=ab 28=bc 29=cb 30=ba
1.2.6 取字符b作为后缀,字符串为:ab,编译表存在,为27,字符串变前缀。前缀:ab;后缀:空;字符串:ab;编码流:1-2-3-2;编译表:27=ab 28=bc 29=cb 30=ba
1.2.7 取字符b作为后缀,字符串为:abb,编译表不存在,定义abb为31,前缀输出,后缀变前缀。前缀:b;后缀:空;字符串:b;编码流:1-2-3-2-27;编译表:27=ab 28=bc 29=cb 30=ba 31=abb
1.2.8 取字符a作为后缀,字符串为:ba,编译表存在,为30,字符串变前缀。前缀:ba;后缀:空;字符串:ba;编码流:1-2-3-2-27;编译表:27=ab 28=bc 29=cb 30=ba 31=abb
1.2.9 取字符c作为后缀,字符串为:bac,编译表不存在,定义bac为32,前缀输出,后缀变前缀。前缀:c;后缀:空;字符串:c;编码流:1-2-3-2-27-30;编译表:27=ab 28=bc 29=cb 30=ba 31=abb 32=bac
1.2.10 输入流没有字符,将前缀c输出,最终编码流为:1-2-3-2-27-30-3
能够看到原来的9个字符被压缩成7个字符。
GIF是基于颜色列表的图片结构,GIF的数据对应的是每个点的颜色在颜色列表的索引,LZW编码是对该索引进行的编码。在GIF格式的图片中,对LZW做了一些改变:
1. 首先定义编码长度,gif中最大编码长度为12位,能表示的最大数字为4096,因此,编译表中序号不能超过4096.
2. gif最大支持256色,因此gif编码长度为9~12位。采用变长编码,到1023,再编码就改为10位,以此类推。
3. gif定义了clear code,清除标记为原始数据长度+1,比如gif最大值为255,那么清除标记为256. 当一个编译的时候,如果编译表达到了最大值,比如4096,就要插入一个clear code,即可以清空编译表,重新开始编译。
4. gif定义了结束标记end,end为清除标记+1, gif中为257,当gif的一张图片编码数据结束后插入end,表示图片结束。
GIF图片编码举例:
输入流:10 21 22 26 10 21 22 10 26
编译表:1~255,256(clear code),257(end)
输入 | 前缀 | 后缀 | 字符串 | 编译表 | 输出 |
10 | 10 | ( ,10) | |||
21 | 10 | 21 | (10, 21) | 258=(10, 21) | 10 |
22 | 21 | 22 | (21, 22) | 259=(21, 22) | 21 |
26 | 22 | 26 | (22, 26) | 260=(22, 26) | 22 |
10 | 26 | 10 | (26, 10) | 261=(26, 10) | 26 |
21 | 10 | 21 | (10, 21) | ||
22 | 258 | 22 | (258, 22) | 262=(258, 22) | 258 |
10 | 22 | 10 | (22. 10) | 263=(22, 10) | 22 |
26 | 10 | 26 | (10, 26) | 264=(10, 26) | 10 |
最后的输出流为:10 21 22 26 258 22 10 26
具体流程图为:
1.2 解码流程
对于1.1中第一个例子,压缩后的编码为1-2-3-2-27-30-3。初始化后的编码表为1~26对应a~z。
1.2.1 读入值1,编译表中存在,输出a,输入做前缀,字符串为a,也在编译表中,前缀为a
1.2.2 读入值2,编译表中存在,输出b,,将b作为后缀,字符串为ab,不在编译表中,定义27=ab,输入做前缀,前缀为b
1.2.3 读入值3,编译表中存在,输出c,将c作为后缀,字符串为bc,不在编译表中,定义28=bc,输入做前缀,前缀为c
1.2.4 读入值2,编译表中存在,输出b,将b作为后缀,字符串为cb,不在编译表中,定义29=cb,输入做前缀,前缀为b
1.2.5 读入值27,编译表中存在,输出ab,将a作为后缀,字符串为ba,不在编译表中,定义30=ba,输入做前缀,前缀为ab
1.2.6 读入值30,编译表中存在,输出ba,将b作为后缀,字符串为abb,在编译表中,输入做前缀为ba
1.2.7 读入值3,编译表中存在,输出c,将c作为后缀,字符串为bac,不在编译表中,定义32=bac,前缀为c
解码后的输出为:abcbabbac
上述第二个例子同理,不再赘述。
如果读入值30后,编译表中不存在,则将上次输入的值+该值的第一个字符输出,将该输出定义为30
流程图为:
3. GraphicsMagic
在使用中发现GM对于有些gif文件无法解析
3.1 bug分析
GM解析gif图片的部分代码:
for (x=0; x < (long) image->columns; ) { if (top_stack == pixel_stack) { if (bits < code_size) { /* Load bytes until there is enough bits for a code. */ if (count == 0) { /* Read a new data block. */ count=ReadBlobBlock(image,packet); if (count == 0) break; c=packet; } datum+=(unsigned long) (*c) << bits; bits+=8; c++; count--; continue; } /* Get the next code. */ code=(long) (datum & code_mask); datum>>=code_size; bits-=code_size; /* Interpret the code */ if (code > available) { status=MagickFail; break; } if (code == end_of_information) break; if (code == clear) { /* Reset decoder. */ code_size=data_size+1; code_mask=(1 << code_size)-1; available=clear+2; old_code=NullCode; continue; } if (old_code == NullCode) { *top_stack++=suffix[code]; old_code=code; first=(unsigned char) code; continue; } in_code=code; if (code >= available) { *top_stack++=first; code=old_code; } while (code >= clear) { if ((top_stack-pixel_stack) >= MaxStackSize) { status=MagickFail; break; } *top_stack++=suffix[code]; code=prefix[code]; } if (status == MagickFail) break; first=suffix[code]; /* Add a new string to the string table, */ if (available >= MaxStackSize) { (void) LogMagickEvent(CoderEvent,GetMagickModule(), "Excessive LZW string data " "(string table overflow)"); status=MagickFail; break; } *top_stack++=first; prefix[available]=(short) old_code; suffix[available]=first; available++; if (((available & code_mask) == 0) && (available < MaxStackSize)) { code_size++; code_mask+=available; } old_code=in_code; } /* Pop a pixel off the pixel stack. */ top_stack--; index=(*top_stack); VerifyColormapIndex(image,index); indexes[x]=index; *q=image->colormap[index]; q->opacity=(Quantum) (index == opacity ? TransparentOpacity : OpaqueOpacity); x++; q++; }
结果发现对于有些gif文件,使用gm进行解析会出错,通过debug发现错误信息为:
Excessive LZW string data (string table overflow)
可知当available>4096时会出现该错误。原因是对于有些gif文件没有严格遵守gif格式,导致解码表超过4096。
3.2 解决方案
将上述红色的代码改为:
if (available < MaxStackSize) { prefix[available]=(short) old_code; suffix[available]=first; available++; if (available >= code_mask + 1 && code_size < 12U) { code_size++; } }
将蓝色的代码去掉。
这样对于超出解码表的像素不再进行解析。
相关推荐
(利用GIF_LZW算法实现的)网络图片传输 技术特点 ~~~~~~~~ 一、使用TCP协议传输数据。理由:稳定性好。 二、使用字节数据流进行传输,理由: A:VB的String存在自动Unicode转换问题,影响速度; B:可以直接发送8位...
VB利用GIF_LZW算法实现网络图片传输,技术特点 一、使用TCP议传输数据。理由:稳定性好。 二、使用字节数据流进行传输,理由: A:VB的String存在自动Unicode转换问题,影响速度; B:可以直接发送8位字节数据...
总结来说,不依赖第三方库的GIF图片压缩用Java实现是一项挑战性的任务,涉及颜色量化和LZW编码两大技术。虽然这种方法可能比使用专门的图像处理库更加复杂,但它提供了更多的控制权和学习机会,对于提升个人技能和...
内容索引:VB源码,网络相关,文件传输 VB利用了GIF_LZW算法实现网络图片传输,也就是Windows XP系统自带的远程桌面登录后的功能,程序仍然采用稳定性好的TCP协议及字节数据流进行传输,减少了编码时间,另外使用GIF-...
本篇文章将深入探讨“简单实用的gif图片解码C语言实现”这一主题,帮助你理解和掌握如何用C语言解析GIF图像文件。 GIF解码过程通常包括以下几个步骤: 1. **文件头解析**:GIF文件以一个固定的6字节文件头开始,...
gif用的变长lzw压缩算法: 没弄懂原理,只知道过程。压缩取一个字符作为后缀,看看字符串是否存在。存在,用对应的编码作为前缀继续取;不存在把字符串添加到字典,前缀添加到输出流,后缀作为前缀继续取。解压取一...
- GIF图片通常采用LZW(Lempel-Ziv-Welch)压缩算法,这是一种字典编码方法,通过查找重复的模式并用更短的代码表示来实现压缩。这种方法可以保持图片质量不变,但压缩率有限。 2. **有损压缩**: - 对于静态GIF...
LZW算法在文件压缩(如GIF图像格式)、数据传输等领域有广泛应用。然而,由于专利问题,LZW在某些场合已被其他无专利限制的压缩算法(如DEFLATE,用于ZIP和PNG格式)所取代。尽管如此,LZW仍然是理解和学习数据压缩...
在C++编程中,实现显示GIF图片的功能是一项挑战,因为GIF是一种支持动画和透明度的复杂图像格式。为了实现这一目标,开发者通常需要利用第三方库或者直接处理GIF的二进制数据。以下是一些关键的知识点,涵盖了如何在...
通过这个"Gif图片分解 源码",开发者不仅可以学习到GIF图像格式的底层知识,还能提升他们在二进制文件处理、图像处理和软件工程方面的技能。这不仅有助于开发自定义的GIF工具,也有助于理解其他图像处理和动画相关的...
GIF格式采用LZW压缩算法,支持256种颜色,这使得它在传输和存储方面具有较高的效率。同时,GIF支持透明度和循环播放,非常适合制作简单的动画。 2. **C#与GIF处理库** 在C#中处理GIF,我们通常会利用第三方库,如...
在选择GIF图片压缩软件时,除了考虑压缩效率和质量,还需要关注软件的安全性和兼容性。确保软件来自可信赖的来源,避免携带病毒或恶意软件。同时,软件应能兼容各种操作系统,并能处理不同版本的GIF文件。 总的来说...
5. **自定义和集成**:开发者和设计师可以根据项目需求选择合适的加载中gif图片,也可以通过代码实现自定义动画,如使用CSS3的`@keyframes`规则或JavaScript库如Animate.css、GSAP等。 6. **资源管理**:将所有加载...
本篇文章将深入探讨如何在BlackBerry平台上创建一个GIF图片显示包装类,并结合BlackBerry线程应用知识,确保程序的性能和流畅性。 首先,理解GIF图片格式是至关重要的。GIF是一种支持动画的位图格式,它通过在一个...
- **格式介绍**:GIF格式使用LZW压缩算法,可以存储多帧图像,形成连续播放的动画效果。 - **颜色限制**:GIF采用8位色彩,最多支持256种颜色,这使得它在色彩丰富的图像上可能不如JPEG或PNG表现好。 - **透明度*...
这个过程涉及一系列复杂的算法和技术,下面将详细阐述GIF图片解码的相关知识点。 1. **GIF文件结构**:GIF文件由头部、逻辑屏幕描述符、全局颜色表、图像描述符、局部颜色表、压缩数据和结束标记等部分组成。解码...
1. **压缩算法**:GIF使用的是LZW(Lempel-Ziv-Welch)无损压缩算法,该算法通过查找和替换重复的字节模式来减少文件大小。这种压缩方法保留了图像的原始质量,但可能无法像有损压缩的JPEG那样实现大幅度的压缩。 2...
压缩图片时,LZW算法通常用于GIF格式,因为GIF支持LZW压缩。对于其他类型的图片,如JPEG和PNG,它们使用的是不同的压缩算法。然而,AS3实现的LZW代码可以用来压缩任何类型的数据,包括非图像数据。 总的来说,AS3中...
总的来说,要在Blackberry设备上显示动态GIF图片,开发者需要对GIF文件格式有深入理解,并能够编写代码来处理和播放GIF动画。"DecodGIF"可能是实现这一功能的关键组件,它封装了GIF解析和动画播放的核心逻辑。通过...
标题中的“gif图片素材.rar”表明这是一个包含gif图像文件的压缩包。GIF,全称Graphics Interchange Format,是一种广泛用于互联网的图像格式,尤其适用于动画。它支持透明度、循环播放以及多帧动画,因此在网站设计...