C#制作透明色GIF动画的类

 

前几天,关注了下GIF的文件结构


 

发现一个GIF文件大小错很多.发现主要是3个地方的问题.


 

一是色彩表的问题.GIF有全局色彩表和图形色彩表.


 

二是GIF图形的大小并不一定是一样的 桢1可能是100*100的 桢2可能是10*10 比如天空是黑色100*100 星星在是10*10


 

三是描述区,没什么作用就是描述


 


 

图形一样大小不一样的就这两个地方区别大.


 


 

用C#来实现下


 

并没用LZW是通过.NET来实现LZW的.这里只是进行了文件头的更改和合并.


 

如果你用这个类打开一个GIF 你通过SAVE方法再保存一次 描述类会放到图形类的后面.

有兴趣到这里逛逛:http://baidv.taobao.com


 


 

使用方式


 



  1.        Zgke.MyImage.ImageGif _Gif = new Zgke.MyImage.ImageGif(20, 32);
  2.  
  3.             int _Temp =(int)'A';
  4.             for (int i = 0; i != 26; i++)
  5.             {
  6.                 Bitmap _BitMap = new Bitmap(20, 32);
  7.                 Graphics _G = Graphics.FromImage(_BitMap);
  8.                 char T = (char)_Temp;
  9.                 _G.DrawString(T.ToString(), new Font("宋体", 20), Brushes.Black, 0, 0);
  10.                 _Gif.AddImage(_BitMap, 1, true, Zgke.MyImage.ImageGif.DisposalMethod.NoDisposalImage);
  11.                 _G.Dispose();
  12.                 _Temp++;
  13.                 _BitMap.Dispose();
  14.             }
  15.             
  16.             pictureBox1.Image = _Gif.Image;
  17.             _Gif.SaveFile(@"C:\1.gif");


 


 

下面是全部的类


 


 


 



  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. using System.Drawing;
  6. using System.Drawing.Imaging;
  7. using System.IO;
  8. using System.Runtime.InteropServices;
  9.  
  10. namespace Zgke.MyImage
  11. {
  12.     /// <summary>
  13.     /// GIF操作类
  14.     /// zgke@sina.com
  15.     /// QQ:116149
  16.     /// </summary>
  17.     public class ImageGif
  18.     {    
  19.         private Header m_Header;
  20.         private LogicalScreen m_LogicalScreen;
  21.         private ColorTable m_GlobalColorTable;
  22.         private IList<ExtensionIntroducer> m_ExtensionIntroducer = new List<ExtensionIntroducer>();
  23.         private ApplicationExtension m_ApplicationExtension;
  24.         private IList<GraphicControlExtension> m_GraphicControlExtension = new List<GraphicControlExtension>();
  25.  
  26.         /// <summary>
  27.         /// 当前位置
  28.         /// </summary>
  29.         private int m_Index = 0;
  30.  
  31.         private bool m_Open = false;
  32.         /// <summary>
  33.         /// 是否正常打开
  34.         /// </summary>
  35.         public bool OpenOK { get { return m_Open; } }
  36.         /// <summary>
  37.         /// 图形数量
  38.         /// </summary>
  39.         public int ImageCount { get { return m_GraphicControlExtension.Count; } }
  40.         /// <summary>
  41.         /// 获取GIF图形
  42.         /// </summary>
  43.         public Image Image
  44.         {
  45.             get 
  46.             {
  47.                 if (m_GraphicControlExtension.Count == 0) return null;
  48.                 MemoryStream _MemoryImage = new MemoryStream();
  49.                 _MemoryImage.Position = 0;
  50.                 byte[] _Temp = m_Header.GetByte();
  51.                 _MemoryImage.Write(_Temp, 0, _Temp.Length);
  52.  
  53.                 _Temp = m_LogicalScreen.GetByte();
  54.                 _MemoryImage.Write(_Temp, 0, _Temp.Length);
  55.  
  56.                 _Temp = m_GlobalColorTable.GetByte();
  57.                 _MemoryImage.Write(_Temp, 0, _Temp.Length);
  58.  
  59.                 _Temp = m_ApplicationExtension.GetByte();
  60.                 _MemoryImage.Write(_Temp, 0, _Temp.Length);
  61.  
  62.                 for (int i = 0; i != m_GraphicControlExtension.Count; i++)  //保存图形
  63.                 {
  64.                     _Temp = m_GraphicControlExtension[i].GetByte();
  65.                     _MemoryImage.Write(_Temp, 0, _Temp.Length);
  66.                 }
  67.                 for (int i = 0; i != m_ExtensionIntroducer.Count; i++)  //保存描述
  68.                 {
  69.                     _Temp = m_ExtensionIntroducer[i].GetByte();
  70.                     _MemoryImage.Write(_Temp, 0, _Temp.Length);
  71.                 }
  72.                 _MemoryImage.WriteByte(0x3B);
  73.  
  74.                 return Image.FromStream(_MemoryImage);
  75.             }            
  76.         }
  77.  
  78.  
  79.         /// <summary>
  80.         /// 由文件打开
  81.         /// </summary>
  82.         /// <param name="p_GifFileName"></param>
  83.         public ImageGif(string p_GifFileName)
  84.         {
  85.             System.IO.FileStream _FileStream = new FileStream(p_GifFileName, FileMode.Open);
  86.             byte[] _GifByte = new byte[_FileStream.Length];
  87.             _FileStream.Read(_GifByte, 0, _GifByte.Length);
  88.             _FileStream.Close();
  89.  
  90.             m_Header = new Header(_GifByte, ref m_Index, ref m_Open);
  91.             if (m_Open == false) return;
  92.             m_LogicalScreen = new LogicalScreen(_GifByte, ref m_Index, ref m_Open);
  93.             if (m_Open == false) return;
  94.             m_GlobalColorTable = new ColorTable(m_LogicalScreen.GlobalPal, m_LogicalScreen.GlobalColorSize, _GifByte, ref m_Index, ref m_Open);
  95.             if (m_Open == false) return;
  96.             //固定位置信息读取完成
  97.  
  98.             m_Open = false;
  99.             while (true)   //不知道有多少个模块一直循环吧
  100.             {
  101.                 #region 判断位置
  102.                 switch (_GifByte[m_Index])
  103.                 {
  104.  
  105.                     case 0x21:
  106.                         m_Index += 2;   //坐标移动到类别后面  取类类别用-1方式 少一行代码
  107.                         switch (_GifByte[m_Index - 1])
  108.                         {
  109.                             case 0xFE:
  110.                                 m_ExtensionIntroducer.Add(new ExtensionIntroducer(_GifByte, ref m_Index, ref m_Open));
  111.                                 if (m_Open == false) return;   //获取失败每必要继续了直接返回
  112.                                 break;
  113.                             case 0xFF:
  114.                                 m_ApplicationExtension = new ApplicationExtension(_GifByte, ref m_Index, ref m_Open);
  115.                                 if (m_Open == false) return;
  116.                                 break;
  117.                             case 0xF9:         //图形在这个区 LZW数据
  118.                                 m_GraphicControlExtension.Add(new GraphicControlExtension(_GifByte, ref m_Index, ref m_Open));
  119.                                 if (m_Open == false) return;
  120.                                 break;
  121.                             default:         //找不到类别 直接结束 
  122.                                 System.Windows.Forms.MessageBox.Show(_GifByte[m_Index - 1].ToString("X02"));
  123.                                 return;
  124.                         }
  125.                         break;
  126.                     case 0x3B:
  127.                         m_Open = true;
  128.                         return;
  129.                     default:
  130.                         m_Open = false;
  131.                         System.Windows.Forms.MessageBox.Show(_GifByte[m_Index].ToString("X02"), m_Index.ToString());
  132.                         return;
  133.                 }
  134.                 #endregion
  135.             }
  136.         }
  137.         /// <summary>
  138.         /// 建立新的图形
  139.         /// </summary>
  140.         /// <param name="p_Width"></param>
  141.         /// <param name="p_Height"></param>
  142.         public ImageGif(ushort p_Width, ushort p_Height)
  143.         {
  144.             m_Header = new Header();
  145.             m_LogicalScreen = new LogicalScreen(p_Width, p_Height);
  146.             m_ApplicationExtension = new ApplicationExtension();
  147.             m_ExtensionIntroducer.Add(new ExtensionIntroducer("http://blog.csdn.net/zgke"));  //这东西可以很多个 描述就是描述 没发现什么作用
  148.  
  149.             
  150.         }
  151.  
  152.  
  153.         #region 添加图形 删除 插入
  154.         /// <summary>
  155.         /// 添加一个图形  
  156.         /// </summary>
  157.         /// <param name="Image">图形</param>
  158.         /// <param name="p_DelayTime">显示时间</param>
  159.         /// <param name="p_UserColorTable">是否使用全局色彩表 true使用 false 不使用</param>
  160.         private GraphicControlExtension GetGraphicsControl(Image p_Image, ushort p_DelayTime, bool p_UserColorTable, DisposalMethod p_Disposal)
  161.         {
  162.             
  163.             MemoryStream _MemOry = new MemoryStream();
  164.  
  165.             Image _Image = ToImageGif((Bitmap)p_Image, Color.White);   //透明的方法可以加到这里
  166.             _Image.Save(_MemOry, ImageFormat.Gif);        //保存成GIF图形
  167.  
  168.             int _Index = 783;   //开始位置781 0x21 0xF9 已经计算
  169.             bool _Open = false;
  170.             GraphicControlExtension _Graphics = new GraphicControlExtension(_MemOry.GetBuffer(), ref _Index, ref _Open);
  171.             _Graphics.DelayTime = p_DelayTime;
  172.             _Graphics.TransparentColorFlag = true;
  173.             _Graphics.TransparentColorIndex = 16;
  174.  
  175.             ColorTable _Table = new ColorTable();
  176.             Image _AddImage = Image.FromStream(_MemOry);  //获取压缩后的图形
  177.  
  178.             for (int i = 0; i != _AddImage.Palette.Entries.Length; i++)      //获取图形颜色表
  179.             {
  180.                 _Table.ColorTableList.Add(_AddImage.Palette.Entries[i]);
  181.             }
  182.  
  183.             if (m_GlobalColorTable == null) m_GlobalColorTable = _Table;     //不管怎么样都要全局色彩表
  184.  
  185.             if (p_UserColorTable == false)
  186.             {
  187.                 _Graphics.ColorTable = _Table;      //根据需要设置全局颜色表              
  188.                 _Graphics.UserColorTable = !p_UserColorTable;
  189.             }
  190.  
  191.             _Graphics.Disposal = p_Disposal;
  192.  
  193.             return _Graphics;
  194.         }
  195.         /// <summary>
  196.         /// 添加一个图形 图形可以大于虚拟屏幕 就是显示不出来而已........
  197.         /// </summary>
  198.         /// <param name="Image">图形</param>
  199.         /// <param name="p_DelayTime">显示时间</param>
  200.         /// <param name="p_UserColorTable">是否使用全局色彩表 true使用 false 不使用</param>
  201.         public void AddImage(Image p_Image, ushort p_DelayTime, bool p_UserColorTable, DisposalMethod p_Disposal)
  202.         {
  203.             GraphicControlExtension _Info = GetGraphicsControl(p_Image, p_DelayTime, p_UserColorTable, p_Disposal);
  204.  
  205.             if (_Info != null) m_GraphicControlExtension.Add(_Info);
  206.         }
  207.  
  208.         /// <summary>
  209.         /// 删除一个图形
  210.         /// </summary>
  211.         /// <param name="p_Index"></param>
  212.         public void RemoveImage(int p_Index)
  213.         {
  214.             if (p_Index > m_GraphicControlExtension.Count - 1) return;
  215.             m_GraphicControlExtension.RemoveAt(p_Index);
  216.         }
  217.         /// <summary>
  218.         /// 插入一个图形
  219.         /// </summary>
  220.         /// <param name="Image">图形</param>
  221.         /// <param name="p_DelayTime">显示时间</param>
  222.         /// <param name="p_UserColorTable">是否使用全局色彩表 true使用 false 不使用</param>
  223.         public void InsertImage(Image p_Image, ushort p_DelayTime, bool p_UserColorTable, int p_Index, DisposalMethod p_Disposal)
  224.         {
  225.             if (p_Index > m_GraphicControlExtension.Count - 1) return;
  226.             GraphicControlExtension _Info = GetGraphicsControl(p_Image, p_DelayTime, p_UserColorTable, p_Disposal);
  227.             if (_Info != null) m_GraphicControlExtension.Insert(p_Index, _Info);
  228.         }
  229.         #endregion
  230.  
  231.         /// <summary>
  232.         /// 设置一个图形播放的时间
  233.         /// </summary>
  234.         /// <param name="p_Index">索引</param>
  235.         /// <param name="p_DelayTime">播放时间</param>
  236.         public void SetImageTime(int p_Index, ushort p_DelayTime)
  237.         {
  238.             if (p_Index > m_GraphicControlExtension.Count - 1) return;
  239.             m_GraphicControlExtension[p_Index].DelayTime = p_DelayTime;
  240.         }
  241.         /// <summary>
  242.         /// 设置一个图形开始位置
  243.         /// </summary>
  244.         /// <param name="p_Index">索引</param>
  245.         /// <param name="p_X">X坐标</param>
  246.         /// <param name="p_Y">Y坐标</param>
  247.         public void SetImageLocatch(int p_Index, Point p_Point)
  248.         {
  249.             if (p_Index > m_GraphicControlExtension.Count - 1) return;
  250.             m_GraphicControlExtension[p_Index].Point = p_Point;
  251.         }
  252.         /// <summary>
  253.         /// 设置处理模式
  254.         /// </summary>
  255.         /// <param name="p_Index">索引</param>
  256.         /// <param name="p_DisposalMethod">处理模式</param>
  257.         public void SetImageDisposalMethod(int p_Index, DisposalMethod p_DisposalMethod)
  258.         {
  259.             if (p_Index > m_GraphicControlExtension.Count - 1) return;
  260.             m_GraphicControlExtension[p_Index].Disposal = p_DisposalMethod;
  261.         }
  262.  
  263.  
  264.  
  265.         /// <summary>
  266.         /// 保存文件
  267.         /// </summary>
  268.         /// <param name="p_FileName"></param>
  269.         public void SaveFile(string p_FileName)
  270.         {
  271.             if (m_GraphicControlExtension.Count == 0) return ;
  272.  
  273.             FileStream _File = new FileStream(p_FileName, FileMode.Create);
  274.             _File.Position = 0;
  275.             byte[] _Temp = m_Header.GetByte();
  276.             _File.Write(_Temp, 0, _Temp.Length);
  277.  
  278.             _Temp = m_LogicalScreen.GetByte();
  279.             _File.Write(_Temp, 0, _Temp.Length);
  280.  
  281.             _Temp = m_GlobalColorTable.GetByte();
  282.             _File.Write(_Temp, 0, _Temp.Length);
  283.  
  284.             _Temp = m_ApplicationExtension.GetByte();
  285.             _File.Write(_Temp, 0, _Temp.Length);
  286.  
  287.             for (int i = 0; i != m_GraphicControlExtension.Count; i++)  //保存图形
  288.             {
  289.                 _Temp = m_GraphicControlExtension[i].GetByte();
  290.                 _File.Write(_Temp, 0, _Temp.Length);
  291.             }
  292.             for (int i = 0; i != m_ExtensionIntroducer.Count; i++)  //保存描述
  293.             {
  294.                 _Temp = m_ExtensionIntroducer[i].GetByte();
  295.                 _File.Write(_Temp, 0, _Temp.Length);
  296.             }
  297.             _File.WriteByte(0x3B);
  298.             _File.Close();
  299.         }
  300.  
  301.         #region 获取图形
  302.         /// <summary>
  303.         /// 内部方法 保存一个图形
  304.         /// </summary>
  305.         /// <param name="m_Stream">数据流</param>
  306.         /// <param name="p_Index">图形索引</param>
  307.         /// <returns>图形</returns>
  308.         private Stream GetImage(Stream m_Stream, int p_Index)
  309.         {
  310.             if (p_Index < 0 || p_Index > ImageCount) return null;
  311.             m_Stream.Position = 0;
  312.             byte[] _Temp = m_Header.GetByte();
  313.             m_Stream.Write(_Temp, 0, _Temp.Length);
  314.  
  315.             _Temp = m_LogicalScreen.GetByte();
  316.             m_Stream.Write(_Temp, 0, _Temp.Length);
  317.  
  318.             _Temp = m_GlobalColorTable.GetByte();
  319.             m_Stream.Write(_Temp, 0, _Temp.Length);
  320.  
  321.             _Temp = m_ApplicationExtension.GetByte();
  322.             m_Stream.Write(_Temp, 0, _Temp.Length);
  323.  
  324.             _Temp = m_GraphicControlExtension[p_Index].GetByte();
  325.             m_Stream.Write(_Temp, 0, _Temp.Length);
  326.  
  327.  
  328.             for (int i = 0; i != m_ExtensionIntroducer.Count; i++)  //保存描述
  329.             {
  330.                 _Temp = m_ExtensionIntroducer[i].GetByte();
  331.                 m_Stream.Write(_Temp, 0, _Temp.Length);
  332.             }
  333.             m_Stream.WriteByte(0x3B);
  334.  
  335.             return m_Stream;
  336.         }
  337.         /// <summary>
  338.         /// 根据索引获取图形
  339.         /// </summary>
  340.         /// <param name="p_Index">索引</param>
  341.         /// <returns>图形</returns>
  342.         public Image GetImage(int p_Index)
  343.         {
  344.             MemoryStream _Memory = new MemoryStream();
  345.  
  346.             return Image.FromStream(GetImage(_Memory, p_Index));
  347.         }
  348.         /// <summary>
  349.         /// 根据索引获取图形
  350.         /// </summary>
  351.         /// <param name="p_Index">索引</param>
  352.         /// <returns>图形</returns>
  353.         public void GetImage(int p_Index, string p_FileName)
  354.         {
  355.             FileStream _File = new FileStream(p_FileName, FileMode.Create);
  356.  
  357.             GetImage(_File, p_Index);
  358.  
  359.             _File.Close();
  360.         }
  361.         #endregion
  362.  
  363.  
  364.  
  365.         /// <summary>
  366.         /// 处理模式
  367.         /// </summary>
  368.         public enum DisposalMethod
  369.         {
  370.             /// <summary>
  371.             /// 不使用处置方法 一般的GIF都是这个
  372.             /// </summary>
  373.             NoDisposalMethod = 0,
  374.             /// <summary>
  375.             /// 不处置图形,把图形从当前位置移去
  376.             /// </summary>
  377.             NoDisposalImage = 1,
  378.             /// <summary>
  379.             /// 回复到背景色
  380.             /// </summary>
  381.             RestoreBackgroundColor = 2,
  382.             /// <summary>
  383.             /// 回复到先前状态
  384.             /// </summary>
  385.             RestoreFrontState = 3,
  386.             /// <summary>
  387.             /// 为定义4-7
  388.             /// </summary>
  389.             Null
  390.  
  391.         }
  392.         #region 类定义
  393.         /// <summary>
  394.         /// GIF文件头
  395.         /// </summary>
  396.         private class Header
  397.         {
  398.             /// <summary>
  399.             ///文件头 必须是GIF
  400.             /// </summary>
  401.             private byte[] _Signature = new byte[] { 0x47, 0x49, 0x46 };
  402.             /// <summary>
  403.             /// 版本信息 
  404.             /// </summary>
  405.             private byte[] _Version = new byte[] { 0x38, 0x39, 0x61 };
  406.  
  407.             public Header(byte[] p_Byte, ref int p_Index, ref bool p_Open)
  408.             {
  409.                 p_Open = false;
  410.                 if (p_Byte[0] != _Signature[0] || p_Byte[1] != _Signature[1] || p_Byte[2] != _Signature[2])
  411.                 {
  412.                     return;
  413.                 }
  414.  
  415.                 _Version[0] = p_Byte[3];
  416.                 _Version[1] = p_Byte[4];
  417.                 _Version[2] = p_Byte[5];
  418.                 p_Index += 6;
  419.                 p_Open = true;
  420.             }
  421.  
  422.             public Header()
  423.             {
  424.  
  425.             }
  426.  
  427.             /// <summary>
  428.             /// 返回版本号 
  429.             /// </summary>
  430.             public string Version
  431.             {
  432.                 get
  433.                 { return Encoding.ASCII.GetString(_Version); }
  434.  
  435.                 set
  436.                 {
  437.                     if (value == "87a") _Version[1] = 0x37;
  438.                 }
  439.             }
  440.  
  441.             public byte[] GetByte()
  442.             {
  443.                 byte[] _Temp = new byte[6];
  444.                 _Temp[0] = _Signature[0];
  445.                 _Temp[1] = _Signature[1];
  446.                 _Temp[2] = _Signature[2];
  447.                 _Temp[3] = _Version[0];
  448.                 _Temp[4] = _Version[1];
  449.                 _Temp[5] = _Version[2];
  450.                 return _Temp;
  451.             }
  452.         }
  453.         /// <summary>
  454.         /// 逻辑屏幕标识符
  455.         /// </summary>
  456.         private class LogicalScreen
  457.         {
  458.             /// <summary>
  459.             /// 图形宽
  460.             /// </summary>
  461.             private byte[] _Width = new byte[2];
  462.             /// <summary>
  463.             /// 图形高
  464.             /// </summary>
  465.             private byte[] _Height = new byte[2];
  466.             /// <summary>
  467.             /// 第8位 - 全局颜色列表标志(Global Color Table Flag),当置位时表示有全局颜色列表,pixel值有意义.
  468.             /// 第5位 第6位 第7位 颜色深度(Color ResoluTion),cr+1确定图象的颜色深度.
  469.             /// 第4位 分类标记 如果置位表示全局颜色列表分类排列.
  470.             /// 第1位 第2位 第3位 全局颜色列表大小,pixel+1确定颜色列表的索引数(2的pixel+1次方).
  471.             /// </summary>
  472.             private byte[] _BitArray = new byte[1];
  473.             /// <summary>
  474.             /// 背景色索引
  475.             /// </summary>
  476.             private byte _Blackground = 0;
  477.             /// <summary>
  478.             /// 像素宽高比
  479.             /// </summary>
  480.             private byte _PixelAspectRadio = 0;
  481.  
  482.             public LogicalScreen(byte[] p_Byte, ref int p_Index, ref bool p_Open)
  483.             {
  484.                 p_Open = false;
  485.                 _Width[0] = p_Byte[p_Index];
  486.                 _Width[1] = p_Byte[p_Index + 1];
  487.                 _Height[0] = p_Byte[p_Index + 2];
  488.                 _Height[1] = p_Byte[p_Index + 3];
  489.                 _BitArray[0] = p_Byte[p_Index + 4];
  490.                 _Blackground = p_Byte[p_Index + 5];
  491.                 _PixelAspectRadio = p_Byte[p_Index + 6];
  492.  
  493.                 p_Index += 7;
  494.  
  495.                 p_Open = true;
  496.             }
  497.  
  498.             public LogicalScreen(ushort p_Width, ushort p_Height)
  499.             {
  500.                 Width = p_Width;
  501.                 Height = p_Height;
  502.                 _Blackground = 0;
  503.                 _PixelAspectRadio = 0;
  504.                 _BitArray[0] = 135;
  505.             }
  506.  
  507.             /// <summary>
  508.             /// 高
  509.             /// </summary>
  510.             public ushort Width { get { return BitConverter.ToUInt16(_Width, 0); } set { _Width = BitConverter.GetBytes(value); } }
  511.             /// <summary>
  512.             /// 宽
  513.             /// </summary>
  514.             public ushort Height { get { return BitConverter.ToUInt16(_Height, 0); } set { _Height = BitConverter.GetBytes(value); } }
  515.             /// <summary>
  516.             /// 背景索引
  517.             /// </summary>
  518.             public byte Blackground { get { return _Blackground; } set { _Blackground = value; } }
  519.             /// <summary>
  520.             /// 像素宽高比
  521.             /// </summary>
  522.             public byte PixelAspectRadio { get { return _PixelAspectRadio; } set { _PixelAspectRadio = value; } }
  523.  
  524.             /// <summary>
  525.             /// 全局颜色列表标志
  526.             /// </summary>
  527.             public bool GlobalPal
  528.             {
  529.                 get
  530.                 {
  531.                     BitArray _BitList = new BitArray(_BitArray);
  532.                     return _BitList[7];
  533.                 }
  534.                 set
  535.                 {
  536.                     BitArray _BitList = new BitArray(_BitArray);

 

原文地址:https://www.cnblogs.com/hyruur/p/gif.html