C#实现合并多个图像文件为一个动态GIF
GIF简介
成都创新互联-专业网站定制、快速模板网站建设、高性价比甘德网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式甘德网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖甘德地区。费用合理售后完善,十年实体公司更值得信赖。
要实现合并为GIF文件,首先要对GIF文件格式有所了解。GIF由 CompuServe在1987年提出,官方文档gif89a标准将GIF分成很多区块,并给出的GIF语法格式如下:
::= Header * Trailer ::= Logical Screen Descriptor [Global Color Table] ::= |
::= [Graphic Control Extension]
::= | Plain Text Extension ::= Image Descriptor [Local Color Table] Image Data ::= Application Extension | Comment Extension
有人用图片的形式整理了语法,看起来更直观:
其中很多区块是可以重复的,它的图像数据模块采用了LZW算法,LZW压缩算法是Compuserv所开发的一种免费算法,然而诡异的是这种算法忽然成了Unisys公司的专利,据Unisys公司称,他们已注册了LZW算法中的W部分。如果要开发生成(或显示)图像互换格式文件的程序,则需向该公司支付版税。Unisys公司的行为曾引起部份开放源代码社区发起“Burn all GIFs”的运动抵制使用GIF。因此,这刺激CompuServe 公司开发了PNG(Portable Network Graphics,便携网络图形)标准,它一方面满足了市场对更少的法规限制的需要,另一方面也带来了更少的技术上的限制,如颜色的数量等。
已有实现
在CodeProject上,有人已经实现了C#版本的GIF图片生成器,代码很多,也很好用。但是对于GIF格式标准不熟悉的人,是看不懂代码的。它的实现完全是采用文件流的方式,根据GIF格式编码语法,生成文件流,甚至还实现了LZW算法来压缩图像。因此这个程序是非常好的学习参考资料。
GDI实现
微软的GDI(Graphics Device Interface)是一套很好的图像开发类库,因此本人觉得为啥那麻烦要用纯文件流的方式去创建GIF,直接用GDI方法去创建GIF不就可以了,微软应该提供这方面的接口的。于是网上找到一些示例代码。实现动态GIF,有个方法就是Image.SaveAdd,它可以实现在现有图片上再加一帧,可是难点在于设置延时时间。对于第一帧的延时的设置很容易实现,但是对于第二帧的延时,一直无效。百思不得其解。
后去Stackoverflow问了一下,得到的回复是微软GDI不支持这种GIF延时,同样百思不得其解。
于是只好土洋结合,对于生成好的GIF,修改其二进制数据,以此实现延时。
用GDI实现设置循环次数和加入帧的代码,不算复杂。C#中可以通过代码修改图片的一些GIF属性,但是不了解GIF编码格式的人还是写不出来的,主要是不知道如何赋值,因为微软官方文档也没给出这部分说明。
比如代码
PropertyItem LoopCount = img.GetPropertyItem(0x5101);//循环次数 //可以去http://msdn.microsoft.com/en-us/library/system.drawing.imaging.propertyitem.id.aspx/css查询 LoopCount.Value = BitConverter.GetBytes(loopCount); img.SetPropertyItem(LoopCount);
0x5101根据文档是循环次数的属性。该属性设置循环次数。GIF文档中,该属性在应用扩展块中,占2个字节16位,按低位高位的顺序排列,是一个无符号的整型。如果01 00表示16进制的0x0001,如果设成00 00 则表示0,循环无限次。
循环次数可以使用GDI控制,但是延时时间在第二帧后就失效了。因此手动更改。
延时时间的属性在图像控制扩展块,对于每一帧图像,都有对应的图像控制扩展块,修改其中的字节即可。图像控制扩展块以21 F9开头,在紧挨着的第三第四字节就是设置延时时间的,单位是百分之一秒。同样的这2个字节也是按低位高位顺序排列的,比如是C8 00,则表示0x00C8=200,也就是延时2秒。
根据以上理论就可以容易的写出设置延时时间的代码。
byte[] bytes = File.ReadAllBytes(savefile); byte[] delaybyte = BitConverter.GetBytes(delay);//转成16位无符号字节数组。该数组肯定只有2个元素 for (int i = 0; i < bytes.Length - 1; i++) { if (bytes[i] == 0x21 && bytes[i + 1] == 0xf9)//GraphicsControlExtension 开始标志 { bytes[i + 4] = delaybyte[0];//这两位就是定义延迟时间的,修改就可以了。 bytes[i + 5] = delaybyte[1]; } }
采用GDI方式,比较简单,偷懒,使用微软做好的现成代码,再稍稍改动就可以了。
参考资料
http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp
http://www.w3.org/Graphics/GIF/spec-gif89a.txt
http://www.codeproject.com/Articles/11505/NGif-Animated-GIF-Encoder-for-NET
http://en.wikipedia.org/wiki/Graphics_Device_Interface
http://www.cnblogs.com/zhengye/articles/2193006.html
《多媒体技术基础》 林福宗
本文标题:C#实现合并多个图像文件为一个动态GIF
标题URL:http://cdiso.cn/article/pijcee.html