C#实现合并多个图像文件为一个动态GIF
2013-07-31 14:38
288 查看
GIF简介
要实现合并为GIF文件,首先要对GIF文件格式有所了解。GIF由 CompuServe在1987年提出,官方文档gif89a标准将GIF分成很多区块,并给出的GIF语法格式如下:
![](http://img1.51cto.com/attachment/201307/31/2359144_1375252689Lcih.gif)
其中很多区块是可以重复的,它的图像数据模块采用了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编码格式的人还是写不出来的,主要是不知道如何赋值,因为微软官方文档也没给出这部分说明。
比如代码
循环次数可以使用GDI控制,但是延时时间在第二帧后就失效了。因此手动更改。
延时时间的属性在图像控制扩展块,对于每一帧图像,都有对应的图像控制扩展块,修改其中的字节即可。图像控制扩展块以21 F9开头,在紧挨着的第三第四字节就是设置延时时间的,单位是百分之一秒。同样的这2个字节也是按低位高位顺序排列的,比如是C8 00,则表示0x00C8=200,也就是延时2秒。
根据以上理论就可以容易的写出设置延时时间的代码。
参考资料
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
要实现合并为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有人用图片的形式整理了语法,看起来更直观:
![](http://img1.51cto.com/attachment/201307/31/2359144_1375252689Lcih.gif)
其中很多区块是可以重复的,它的图像数据模块采用了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
相关文章推荐
- C#实现合并多个图像文件为一个动态GIF(转)
- C#实现文本文件合并
- C#修改config文件实现动态调用webservice实现问题
- sql server 关于表中只增标识问题 C# 实现自动化打开和关闭可执行文件(或 关闭停止与系统交互的可执行文件) ajaxfileupload插件上传图片功能,用MVC和aspx做后台各写了一个案例 将小写阿拉伯数字转换成大写的汉字, C# WinForm 中英文实现, 国际化实现的简单方法 ASP.NET Core 2 学习笔记(六)ASP.NET Core 2 学习笔记(三)
- K个有序链表共N个结点在O(NlgK)时间合并为一个新的有序链表实现文件C语言
- c# 实现2个程序同时操作读写一个文件、一个读一个写
- python实现将文件夹内所有txt文件合并成一个文件
- Python实现将目录中TXT合并成一个大TXT文件的方法
- 一个简单的QQ隐藏图生成算法 通过jQuery和C#分别实现对.NET Core Web Api的访问以及文件上传
- C#读取配置文件详解 完全自定义实现动态加载dll
- C#编程实现动态改变配置文件信息的方法
- [C# 网络编程系列]专题十一:实现一个基于FTP协议的程序——文件上传下载器
- C#实现文本文件合并
- c#实现将一个文件夹中的所有文件复制到另一个文件夹,并在新文件夹中创建一个txt文件记录copy的文件综述以及文件名称
- Python实现合并同一个文件夹下所有PDF文件的方法示例
- C#动态修改文件夹名称(FSO实现,不移动文件)
- C# :实现水印与图片合成,并利用Graphics 压缩图像质量 , (委托实现listBox的动态添加提示)
- c# 动态实现xls,dwg等文件存取sqlserver数据库
- C#实现文本文件合并
- C#实现合并及拆分PDF文件的方法