前几天,关注了下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
使用方式
- Zgke.MyImage.ImageGif _Gif = new Zgke.MyImage.ImageGif(20, 32);
-
- int _Temp =(int)'A';
- for (int i = 0; i != 26; i++)
- {
- Bitmap _BitMap = new Bitmap(20, 32);
- Graphics _G = Graphics.FromImage(_BitMap);
- char T = (char)_Temp;
- _G.DrawString(T.ToString(), new Font("宋体", 20), Brushes.Black, 0, 0);
- _Gif.AddImage(_BitMap, 1, true, Zgke.MyImage.ImageGif.DisposalMethod.NoDisposalImage);
- _G.Dispose();
- _Temp++;
- _BitMap.Dispose();
- }
-
- pictureBox1.Image = _Gif.Image;
- _Gif.SaveFile(@"C:\1.gif");
下面是全部的类
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Text;
- using System.Drawing;
- using System.Drawing.Imaging;
- using System.IO;
- using System.Runtime.InteropServices;
-
- namespace Zgke.MyImage
- {
- /// <summary>
- /// GIF操作类
- /// [email protected]
- /// QQ:116149
- /// </summary>
- public class ImageGif
- {
- private Header m_Header;
- private LogicalScreen m_LogicalScreen;
- private ColorTable m_GlobalColorTable;
- private IList<ExtensionIntroducer> m_ExtensionIntroducer = new List<ExtensionIntroducer>();
- private ApplicationExtension m_ApplicationExtension;
- private IList<GraphicControlExtension> m_GraphicControlExtension = new List<GraphicControlExtension>();
-
- /// <summary>
- /// 当前位置
- /// </summary>
- private int m_Index = 0;
-
- private bool m_Open = false;
- /// <summary>
- /// 是否正常打开
- /// </summary>
- public bool OpenOK { get { return m_Open; } }
- /// <summary>
- /// 图形数量
- /// </summary>
- public int ImageCount { get { return m_GraphicControlExtension.Count; } }
- /// <summary>
- /// 获取GIF图形
- /// </summary>
- public Image Image
- {
- get
- {
- if (m_GraphicControlExtension.Count == 0) return null;
- MemoryStream _MemoryImage = new MemoryStream();
- _MemoryImage.Position = 0;
- byte[] _Temp = m_Header.GetByte();
- _MemoryImage.Write(_Temp, 0, _Temp.Length);
-
- _Temp = m_LogicalScreen.GetByte();
- _MemoryImage.Write(_Temp, 0, _Temp.Length);
-
- _Temp = m_GlobalColorTable.GetByte();
- _MemoryImage.Write(_Temp, 0, _Temp.Length);
-
- _Temp = m_ApplicationExtension.GetByte();
- _MemoryImage.Write(_Temp, 0, _Temp.Length);
-
- for (int i = 0; i != m_GraphicControlExtension.Count; i++) //保存图形
- {
- _Temp = m_GraphicControlExtension[i].GetByte();
- _MemoryImage.Write(_Temp, 0, _Temp.Length);
- }
- for (int i = 0; i != m_ExtensionIntroducer.Count; i++) //保存描述
- {
- _Temp = m_ExtensionIntroducer[i].GetByte();
- _MemoryImage.Write(_Temp, 0, _Temp.Length);
- }
- _MemoryImage.WriteByte(0x3B);
-
- return Image.FromStream(_MemoryImage);
- }
- }
-
-
- /// <summary>
- /// 由文件打开
- /// </summary>
- /// <param name="p_GifFileName"></param>
- public ImageGif(string p_GifFileName)
- {
- System.IO.FileStream _FileStream = new FileStream(p_GifFileName, FileMode.Open);
- byte[] _GifByte = new byte[_FileStream.Length];
- _FileStream.Read(_GifByte, 0, _GifByte.Length);
- _FileStream.Close();
-
- m_Header = new Header(_GifByte, ref m_Index, ref m_Open);
- if (m_Open == false) return;
- m_LogicalScreen = new LogicalScreen(_GifByte, ref m_Index, ref m_Open);
- if (m_Open == false) return;
- m_GlobalColorTable = new ColorTable(m_LogicalScreen.GlobalPal, m_LogicalScreen.GlobalColorSize, _GifByte, ref m_Index, ref m_Open);
- if (m_Open == false) return;
- //固定位置信息读取完成
-
- m_Open = false;
- while (true) //不知道有多少个模块一直循环吧
- {
- #region 判断位置
- switch (_GifByte[m_Index])
- {
-
- case 0x21:
- m_Index += 2; //坐标移动到类别后面 取类类别用-1方式 少一行代码
- switch (_GifByte[m_Index - 1])
- {
- case 0xFE:
- m_ExtensionIntroducer.Add(new ExtensionIntroducer(_GifByte, ref m_Index, ref m_Open));
- if (m_Open == false) return; //获取失败每必要继续了直接返回
- break;
- case 0xFF:
- m_ApplicationExtension = new ApplicationExtension(_GifByte, ref m_Index, ref m_Open);
- if (m_Open == false) return;
- break;
- case 0xF9: //图形在这个区 LZW数据
- m_GraphicControlExtension.Add(new GraphicControlExtension(_GifByte, ref m_Index, ref m_Open));
- if (m_Open == false) return;
- break;
- default: //找不到类别 直接结束
- System.Windows.Forms.MessageBox.Show(_GifByte[m_Index - 1].ToString("X02"));
- return;
- }
- break;
- case 0x3B:
- m_Open = true;
- return;
- default:
- m_Open = false;
- System.Windows.Forms.MessageBox.Show(_GifByte[m_Index].ToString("X02"), m_Index.ToString());
- return;
- }
- #endregion
- }
- }
- /// <summary>
- /// 建立新的图形
- /// </summary>
- /// <param name="p_Width"></param>
- /// <param name="p_Height"></param>
- public ImageGif(ushort p_Width, ushort p_Height)
- {
- m_Header = new Header();
- m_LogicalScreen = new LogicalScreen(p_Width, p_Height);
- m_ApplicationExtension = new ApplicationExtension();
- m_ExtensionIntroducer.Add(new ExtensionIntroducer("http://blog.csdn.net/zgke")); //这东西可以很多个 描述就是描述 没发现什么作用
-
-
- }
-
-
- #region 添加图形 删除 插入
- /// <summary>
- /// 添加一个图形
- /// </summary>
- /// <param name="Image">图形</param>
- /// <param name="p_DelayTime">显示时间</param>
- /// <param name="p_UserColorTable">是否使用全局色彩表 true使用 false 不使用</param>
- private GraphicControlExtension GetGraphicsControl(Image p_Image, ushort p_DelayTime, bool p_UserColorTable, DisposalMethod p_Disposal)
- {
-
- MemoryStream _MemOry = new MemoryStream();
-
- Image _Image = ToImageGif((Bitmap)p_Image, Color.White); //透明的方法可以加到这里
- _Image.Save(_MemOry, ImageFormat.Gif); //保存成GIF图形
-
- int _Index = 783; //开始位置781 0x21 0xF9 已经计算
- bool _Open = false;
- GraphicControlExtension _Graphics = new GraphicControlExtension(_MemOry.GetBuffer(), ref _Index, ref _Open);
- _Graphics.DelayTime = p_DelayTime;
- _Graphics.TransparentColorFlag = true;
- _Graphics.TransparentColorIndex = 16;
-
- ColorTable _Table = new ColorTable();
- Image _AddImage = Image.FromStream(_MemOry); //获取压缩后的图形
-
- for (int i = 0; i != _AddImage.Palette.Entries.Length; i++) //获取图形颜色表
- {
- _Table.ColorTableList.Add(_AddImage.Palette.Entries[i]);
- }
-
- if (m_GlobalColorTable == null) m_GlobalColorTable = _Table; //不管怎么样都要全局色彩表
-
- if (p_UserColorTable == false)
- {
- _Graphics.ColorTable = _Table; //根据需要设置全局颜色表
- _Graphics.UserColorTable = !p_UserColorTable;
- }
-
- _Graphics.Disposal = p_Disposal;
-
- return _Graphics;
- }
- /// <summary>
- /// 添加一个图形 图形可以大于虚拟屏幕 就是显示不出来而已........
- /// </summary>
- /// <param name="Image">图形</param>
- /// <param name="p_DelayTime">显示时间</param>
- /// <param name="p_UserColorTable">是否使用全局色彩表 true使用 false 不使用</param>
- public void AddImage(Image p_Image, ushort p_DelayTime, bool p_UserColorTable, DisposalMethod p_Disposal)
- {
- GraphicControlExtension _Info = GetGraphicsControl(p_Image, p_DelayTime, p_UserColorTable, p_Disposal);
-
- if (_Info != null) m_GraphicControlExtension.Add(_Info);
- }
-
- /// <summary>
- /// 删除一个图形
- /// </summary>
- /// <param name="p_Index"></param>
- public void RemoveImage(int p_Index)
- {
- if (p_Index > m_GraphicControlExtension.Count - 1) return;
- m_GraphicControlExtension.RemoveAt(p_Index);
- }
- /// <summary>
- /// 插入一个图形
- /// </summary>
- /// <param name="Image">图形</param>
- /// <param name="p_DelayTime">显示时间</param>
- /// <param name="p_UserColorTable">是否使用全局色彩表 true使用 false 不使用</param>
- public void InsertImage(Image p_Image, ushort p_DelayTime, bool p_UserColorTable, int p_Index, DisposalMethod p_Disposal)
- {
- if (p_Index > m_GraphicControlExtension.Count - 1) return;
- GraphicControlExtension _Info = GetGraphicsControl(p_Image, p_DelayTime, p_UserColorTable, p_Disposal);
- if (_Info != null) m_GraphicControlExtension.Insert(p_Index, _Info);
- }
- #endregion
-
- /// <summary>
- /// 设置一个图形播放的时间
- /// </summary>
- /// <param name="p_Index">索引</param>
- /// <param name="p_DelayTime">播放时间</param>
- public void SetImageTime(int p_Index, ushort p_DelayTime)
- {
- if (p_Index > m_GraphicControlExtension.Count - 1) return;
- m_GraphicControlExtension[p_Index].DelayTime = p_DelayTime;
- }
- /// <summary>
- /// 设置一个图形开始位置
- /// </summary>
- /// <param name="p_Index">索引</param>
- /// <param name="p_X">X坐标</param>
- /// <param name="p_Y">Y坐标</param>
- public void SetImageLocatch(int p_Index, Point p_Point)
- {
- if (p_Index > m_GraphicControlExtension.Count - 1) return;
- m_GraphicControlExtension[p_Index].Point = p_Point;
- }
- /// <summary>
- /// 设置处理模式
- /// </summary>
- /// <param name="p_Index">索引</param>
- /// <param name="p_DisposalMethod">处理模式</param>
- public void SetImageDisposalMethod(int p_Index, DisposalMethod p_DisposalMethod)
- {
- if (p_Index > m_GraphicControlExtension.Count - 1) return;
- m_GraphicControlExtension[p_Index].Disposal = p_DisposalMethod;
- }
-
-
-
- /// <summary>
- /// 保存文件
- /// </summary>
- /// <param name="p_FileName"></param>
- public void SaveFile(string p_FileName)
- {
- if (m_GraphicControlExtension.Count == 0) return ;
-
- FileStream _File = new FileStream(p_FileName, FileMode.Create);
- _File.Position = 0;
- byte[] _Temp = m_Header.GetByte();
- _File.Write(_Temp, 0, _Temp.Length);
-
- _Temp = m_LogicalScreen.GetByte();
- _File.Write(_Temp, 0, _Temp.Length);
-
- _Temp = m_GlobalColorTable.GetByte();
- _File.Write(_Temp, 0, _Temp.Length);
-
- _Temp = m_ApplicationExtension.GetByte();
- _File.Write(_Temp, 0, _Temp.Length);
-
- for (int i = 0; i != m_GraphicControlExtension.Count; i++) //保存图形
- {
- _Temp = m_GraphicControlExtension[i].GetByte();
- _File.Write(_Temp, 0, _Temp.Length);
- }
- for (int i = 0; i != m_ExtensionIntroducer.Count; i++) //保存描述
- {
- _Temp = m_ExtensionIntroducer[i].GetByte();
- _File.Write(_Temp, 0, _Temp.Length);
- }
- _File.WriteByte(0x3B);
- _File.Close();
- }
-
- #region 获取图形
- /// <summary>
- /// 内部方法 保存一个图形
- /// </summary>
- /// <param name="m_Stream">数据流</param>
- /// <param name="p_Index">图形索引</param>
- /// <returns>图形</returns>
- private Stream GetImage(Stream m_Stream, int p_Index)
- {
- if (p_Index < 0 || p_Index > ImageCount) return null;
- m_Stream.Position = 0;
- byte[] _Temp = m_Header.GetByte();
- m_Stream.Write(_Temp, 0, _Temp.Length);
-
- _Temp = m_LogicalScreen.GetByte();
- m_Stream.Write(_Temp, 0, _Temp.Length);
-
- _Temp = m_GlobalColorTable.GetByte();
- m_Stream.Write(_Temp, 0, _Temp.Length);
-
- _Temp = m_ApplicationExtension.GetByte();
- m_Stream.Write(_Temp, 0, _Temp.Length);
-
- _Temp = m_GraphicControlExtension[p_Index].GetByte();
- m_Stream.Write(_Temp, 0, _Temp.Length);
-
-
- for (int i = 0; i != m_ExtensionIntroducer.Count; i++) //保存描述
- {
- _Temp = m_ExtensionIntroducer[i].GetByte();
- m_Stream.Write(_Temp, 0, _Temp.Length);
- }
- m_Stream.WriteByte(0x3B);
-
- return m_Stream;
- }
- /// <summary>
- /// 根据索引获取图形
- /// </summary>
- /// <param name="p_Index">索引</param>
- /// <returns>图形</returns>
- public Image GetImage(int p_Index)
- {
- MemoryStream _Memory = new MemoryStream();
-
- return Image.FromStream(GetImage(_Memory, p_Index));
- }
- /// <summary>
- /// 根据索引获取图形
- /// </summary>
- /// <param name="p_Index">索引</param>
- /// <returns>图形</returns>
- public void GetImage(int p_Index, string p_FileName)
- {
- FileStream _File = new FileStream(p_FileName, FileMode.Create);
-
- GetImage(_File, p_Index);
-
- _File.Close();
- }
- #endregion
-
-
-
- /// <summary>
- /// 处理模式
- /// </summary>
- public enum DisposalMethod
- {
- /// <summary>
- /// 不使用处置方法 一般的GIF都是这个
- /// </summary>
- NoDisposalMethod = 0,
- /// <summary>
- /// 不处置图形,把图形从当前位置移去
- /// </summary>
- NoDisposalImage = 1,
- /// <summary>
- /// 回复到背景色
- /// </summary>
- RestoreBackgroundColor = 2,
- /// <summary>
- /// 回复到先前状态
- /// </summary>
- RestoreFrontState = 3,
- /// <summary>
- /// 为定义4-7
- /// </summary>
- Null
-
- }
- #region 类定义
- /// <summary>
- /// GIF文件头
- /// </summary>
- private class Header
- {
- /// <summary>
- ///文件头 必须是GIF
- /// </summary>
- private byte[] _Signature = new byte[] { 0x47, 0x49, 0x46 };
- /// <summary>
- /// 版本信息
- /// </summary>
- private byte[] _Version = new byte[] { 0x38, 0x39, 0x61 };
-
- public Header(byte[] p_Byte, ref int p_Index, ref bool p_Open)
- {
- p_Open = false;
- if (p_Byte[0] != _Signature[0] || p_Byte[1] != _Signature[1] || p_Byte[2] != _Signature[2])
- {
- return;
- }
-
- _Version[0] = p_Byte[3];
- _Version[1] = p_Byte[4];
- _Version[2] = p_Byte[5];
- p_Index += 6;
- p_Open = true;
- }
-
- public Header()
- {
-
- }
-
- /// <summary>
- /// 返回版本号
- /// </summary>
- public string Version
- {
- get
- { return Encoding.ASCII.GetString(_Version); }
-
- set
- {
- if (value == "87a") _Version[1] = 0x37;
- }
- }
-
- public byte[] GetByte()
- {
- byte[] _Temp = new byte[6];
- _Temp[0] = _Signature[0];
- _Temp[1] = _Signature[1];
- _Temp[2] = _Signature[2];
- _Temp[3] = _Version[0];
- _Temp[4] = _Version[1];
- _Temp[5] = _Version[2];
- return _Temp;
- }
- }
- /// <summary>
- /// 逻辑屏幕标识符
- /// </summary>
- private class LogicalScreen
- {
- /// <summary>
- /// 图形宽
- /// </summary>
- private byte[] _Width = new byte[2];
- /// <summary>
- /// 图形高
- /// </summary>
- private byte[] _Height = new byte[2];
- /// <summary>
- /// 第8位 - 全局颜色列表标志(Global Color Table Flag),当置位时表示有全局颜色列表,pixel值有意义.
- /// 第5位 第6位 第7位 颜色深度(Color ResoluTion),cr+1确定图象的颜色深度.
- /// 第4位 分类标记 如果置位表示全局颜色列表分类排列.
- /// 第1位 第2位 第3位 全局颜色列表大小,pixel+1确定颜色列表的索引数(2的pixel+1次方).
- /// </summary>
- private byte[] _BitArray = new byte[1];
- /// <summary>
- /// 背景色索引
- /// </summary>
- private byte _Blackground = 0;
- /// <summary>
- /// 像素宽高比
- /// </summary>
- private byte _PixelAspectRadio = 0;
-
- public LogicalScreen(byte[] p_Byte, ref int p_Index, ref bool p_Open)
- {
- p_Open = false;
- _Width[0] = p_Byte[p_Index];
- _Width[1] = p_Byte[p_Index + 1];
- _Height[0] = p_Byte[p_Index + 2];
- _Height[1] = p_Byte[p_Index + 3];
- _BitArray[0] = p_Byte[p_Index + 4];
- _Blackground = p_Byte[p_Index + 5];
- _PixelAspectRadio = p_Byte[p_Index + 6];
-
- p_Index += 7;
-
- p_Open = true;
- }
-
- public LogicalScreen(ushort p_Width, ushort p_Height)
- {
- Width = p_Width;
- Height = p_Height;
- _Blackground = 0;
- _PixelAspectRadio = 0;
- _BitArray[0] = 135;
- }
-
- /// <summary>
- /// 高
- /// </summary>
- public ushort Width { get { return BitConverter.ToUInt16(_Width, 0); } set { _Width = BitConverter.GetBytes(value); } }
- /// <summary>
- /// 宽
- /// </summary>
- public ushort Height { get { return BitConverter.ToUInt16(_Height, 0); } set { _Height = BitConverter.GetBytes(value); } }
- /// <summary>
- /// 背景索引
- /// </summary>
- public byte Blackground { get { return _Blackground; } set { _Blackground = value; } }
- /// <summary>
- /// 像素宽高比
- /// </summary>
- public byte PixelAspectRadio { get { return _PixelAspectRadio; } set { _PixelAspectRadio = value; } }
-
- /// <summary>
- /// 全局颜色列表标志
- /// </summary>
- public bool GlobalPal
- {
- get
- {
- BitArray _BitList = new BitArray(_BitArray);
- return _BitList[7];
- }
- set
- {
- BitArray _BitList = new BitArray(_BitArray);
|
请发表评论