C#实现合并多个图像文件为一个动态GIF(转)

GIF简介

要实现合并为GIF文件,首先要对GIF文件格式有所了解。GIF由 CompuServe在1987年提出,官方文档gif89a标准将GIF分成很多区块,并给出的GIF语法格式如下:

<GIF Data Stream> ::=     Header <Logical Screen> <Data>* Trailer

<Logical Screen> ::=      Logical Screen Descriptor [Global Color Table]

<Data> ::=                <Graphic Block>  |
                          <Special-Purpose Block>

<Graphic Block> ::=       [Graphic Control Extension] <Graphic-Rendering Block>

<Graphic-Rendering Block> ::=  <Table-Based Image>  |
                               Plain Text Extension

<Table-Based Image> ::=   Image Descriptor [Local Color Table] Image Data

<Special-Purpose Block> ::=    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

《多媒体技术基础》 林福宗

本文出自 “一只博客” 博客,请务必保留此出处http://cnn237111.blog.51cto.com/2359144/1261422

原文地址:https://www.cnblogs.com/zzyhost/p/3594095.html