zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    【WPF】数据验证
    CSS 属性:touch-action
    sublime text3 中设置默认浏览器,并且设置快捷键
    Git克隆、修改、更新项目,及查看项目地址命令
    监听文本框输入oninput和onpropertychange事件
    css基础笔记
    纯css,div隐藏滚动条,保留鼠标滚动效果。
    打印机如何取消打印任务
    git使用上
    Git设置记住账号密码
  • 原文地址:https://www.cnblogs.com/zzyhost/p/3594095.html
Copyright © 2011-2022 走看看