《GIF图片原理和储存结构深入解析》要点:
本文介绍了GIF图片原理和储存结构深入解析,希望对您有用。如果有疑问,可以联系我们。
GIF是一种使用LZW压缩,支持多张图像的容器.支持256色,透明通道为1bit.作为互联网表情包的载体,GIF这项80年代的技术依然生生不息.
但它的弊病也是显而易见的:易出现毛边,色彩表现低劣,文件压缩比不高.针对这些问题,Mozilla发布了APNG来代替老旧的GIF技术,同时许多开源组件也用WebP格式来代替GIF.
长久以来,iOS一直被吐槽不克不及用GIF.造成这一局面的主要原因是:
imageI/O
去操作GIF数据,UIKit对其绝缘.由于历史的原因,GIF有两个版本,但它们的文件结构是一样的,都是由不同用途的数据块构成,可分为控制块和数据块.控制块里是决定GIF表现的参数,数据块里的数据由前面的控制块里的参数来解释.
一个GIF文件的内部结构如下图:
GIF布局
Header:包括文件签名与版本号.
Trailer: 文件结束标识符.
GIF Data: Header 与 trailer 之间就是GIF文件的数据.
我们从一个简单的GIF图入手,它包括两张图像:
这是它的十六进制数据,我用颜色区分了分歧的数据块:
Paste_Image.png
GIF文件的开头是 Header 数据块,长度为6字节,ASCII值为“GIF87a”或”GIF89a”,前三位为GIF签名,后三位为分歧年份的版本号.
Paste_Image.png
利用这点,在iOS中判断二进制文件是否为GIF时,可以简单去判断它的前四位是否是”GIF8″.事实上绝年夜多数图像都可以用文件签名来判断类型.
GIF数据包括多个数据块,其结构如下:
逻辑屏幕描述符
0A000A00 B30000
这一数据块由7个字节组成,前四个字节分别是图像渲染区域的宽高.GIF的数据是依照大端序存储的,0x0A00为10,所以这个GIF的宽高均为10.
接下来是一个压缩字节,第一个 Bit 为标志位,表示全局颜色列表是否存在.接下来三个Bit表示图像调色板中每个颜色的原色所占用的Bit数,011表示占用4个Bit,111占用8个Bit,以此类推.调色板最多只包含由24-Bit颜色中选出的256个颜色(实际有很多优化方案能提高颜色分辨率,如加入局部调色板).第五个Bit为标志位,表示颜色列表排序方式.若为1,表示颜色列表是依照颜色在图像中出现的频率降序排列.随后三个Bit表示全局颜色列表的大小,计算方法是2^N+1 ,其中N为这三个Bit的二进制数值.
第六个字节是表示背景色在全局颜色列表中的索引,若无全局颜色列表则此字节无效.在GIF的图像数据中,没有被指定颜色的像素会被背景色填充.
最后一个字节是像素的宽高比,大多数时候这个值都是0,若值为N, 则图像的宽高比:
aspectRatio = (pixelAspectRatio + 15) / 64
全局色彩列表
000000 80000000 80008080 00000080 80008000 8080C0C0 C0808080 FF000000 FF00FFFF 000000FF FF00FF00 FFFFFFFF FF
由前面的逻辑屏幕描述符可知,全局颜色列表的大小是16,每个颜色占三个字节,依照RGB排列,所以它占有48个字节.数据流中,颜色是依照列表中的索引存储的.
应用程序扩展
>
21FF0B 4E455453 43415045 322E3003 01000000
GIF中扩展块都以0x21开始,后一个字节是扩展标签,标识扩展用途.
应用程序扩展的标签是0xFF,它包括有应用程序的标识信息和应用程序数据.其中 Netscape 应用程序扩展常用于控制GIF的动画循环次数.Netscape 扩展长19个字节,前14个是应用程序的ACSII信息,后四个是数据子块,用于指定GIF的循环次数, 按无符号整型存储,0表示无限循环.
图形节制扩展
21F90409 32000F00
图形控制扩展块属于”89a”版本的定义.它在一个图像数据块的最前端,用来指定图像的透明度与动画属性.图形控制扩展的开端两字节是0x21F9,其中0x21表示这是一个扩展,F9表示扩展用于图形控制.第三个字节是块大小(它到结束符之间的数据).第四个字节是压缩字段,前三个Bit保存,四到六Bit是disposal method.第四、五个字节是图像控制扩展后面的图像的动画时间,以无符号整型存储.第六个字节是透明色索引,之后是块结束符0x00.
图像描写符
2C000000 000A000A 0000
图像描述符位于GIF中每一个图像数据的前端,由0x2C开始,长度为10个字节.第一个字节是图像描述符的标识0x2c,后面八个字节表现图像的frame(left, top, width, height),用来在动画中局部更新图像.最后一个是压缩字节,主要是关于局部颜色列表的信息,其中第二个Bit表现图像的存储方式是交织还是连续.
局部颜色列表
如果上面的局部颜色列表标志位为1,那么局部颜色列表会排列在图像描述符后面,它只对紧跟在它之后的图像数据有效.如果局部颜色列表标志位为0,那么图像数据将使用全局颜色列表索引颜色.局部颜色列表的大小计算办法和像素颜色格式与全局颜色列表相同.
图像数据
041C 1080472B 0549DA9B BAAE58E7 4D4F288E E629A519 697E1C0C 92DB1301 00
GIF的图像数据是经过LZW压缩的二进制流,通过解码可以将其依照颜色列表中的颜色进行像素填充.第一个字节是LZW最小编码大小,用来进行数据解码.第二个字节是图像数据的大小,之后的都是图像数据,直到块结束符.
结束符
3B
GIF动画的循环次数是由应用扩展来控制的,而GIF动画每一帧的过渡方式是由图形控制扩展控制,图像描述符控制图像绘制的区域.
图形控制扩展中控制动画的参数分离是:disposal method
,user input flag
,delay time
,transparency color
.
disposal methoddisposal method
占3Bit,能够表现0-7.
解码器不会清算画布,直接将下一幅图像渲染上一幅图像上.
解码器会以配景色清理画布,然后渲染下一幅图像.配景色在逻辑屏幕描述符中设置.
解码器会将画布设置为上之前的状态,然后衬着下一幅图像.
保存值
user input flag
当user input flag
为1时,GIF会在有用户输入变乱(鼠标、键盘)时才会过渡到下一幅图像.
delay timedelay time
占两个字节,为无符号整数,控制当前帧的展示时间,单元是0.01秒.
transparency color
如果图形控制扩展的透明色标志位为1,那么解码器会通过透明色索引在颜色列表中找到改颜色,标记为透明,当渲染图像时,标记为透明色的颜色将不会绘制,显示下面的配景.
图像渲染区域
GIF中图像描述符指定了当前帧必要渲染的区域,这样GIF的过渡动画就只用绘制两帧之间不同的区域,前提是diposal method
的值为1.
依据上面的知识,将第一帧的图形控制扩展改为:
21F90409 0A000900
这里将透明色改成了赤色(赤色在全局颜色列表中的索引是9),并将delay time
改为0.1秒.修改完的GIF为:
本文永远更新链接地址:http://www.linuxidc.com/Linux/2017-06/145156.htm
更多LINUX教程,尽在维易PHP学院专栏。欢迎交流《GIF图片原理和储存结构深入解析》!