using System; using System.Drawing; using System.Drawing.Imaging; using System.IO; namespace Lumpio.Gif { public class GifWriter { private int width, height; private Image paletteImage; private Stream stream; private GifPalette palette; public GifPalette Palette { get { return palette; } set { palette = value; } } private byte bgColor; public byte BgColor { get { return bgColor; } set { bgColor = value; } } public GifWriter(int width, int height, Stream stream) { this.width = width; this.height = height; this.stream = stream; this.palette = new GifPalette(); //paletteImage = new Bitmap(1, 1, PixelFormat.Format8bppIndexed); //Console.WriteLine(paletteImage.Palette.Entries.Length); } /*public void SetPalette(byte index, byte r, byte g, byte b) { SetPalette(index, (r << 16) | (g << 8) | b); } public void SetPalette(byte index, int c) { //ColorPalette pal = paletteImage.Palette; //pal.Entries[index] = Color.FromArgb(c); //paletteImage.Palette = pal; palette[index] = Color.FromArgb(c); }*/ public Bitmap GetImage() { Bitmap bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed); for (int i = 0; i <= 255; ++i) { bmp.Palette.Entries[i] = paletteImage.Palette.Entries[i]; } return bmp; } public void WriteHeaders() { writeHeadersInternal(stream); } public byte[] GetHeaders() { MemoryStream s = new MemoryStream(); writeHeadersInternal(s); return s.ToArray(); } private void writeHeadersInternal(Stream s) { BinaryWriter bw = new BinaryWriter(s); bw.Write(new byte[]{ (byte)'G', (byte)'I', (byte)'F', (byte)'8', (byte)'9', (byte)'a', }); bw.Write((ushort)width); bw.Write((ushort)height); bw.Write((byte)0xF7); bw.Write(this.bgColor); bw.Write((byte)0x00); for (int i = 0; i < 256; ++i) { // Color c = frame.Palette.Entries[i]; Color c = palette[i]; bw.Write(new byte[]{c.R, c.G, c.B}); } } public void WriteTrailer() { stream.WriteByte((byte)0x3B); } public byte[] GetTrailer() { return new byte[]{0x3B}; } public void WriteFrame(/*Bitmap frame*/ byte[] data) { writeFrameInternal(stream, data); } public byte[] GetFrame(/*Bitmap frame*/ byte[] data) { MemoryStream s = new MemoryStream(); writeFrameInternal(s, data); return s.ToArray(); } private void writeFrameInternal(Stream s, /* Bitmap frame*/ byte[] data) { GifCompressor gc = new GifCompressor(s); BinaryWriter bw = new BinaryWriter(s); bw.Write((byte)0x2C); bw.Write((ushort)0x00); bw.Write((ushort)0x00); bw.Write((ushort)width); bw.Write((ushort)height); bw.Write((byte)0x00); /*byte[] data = new byte[width * height]; unsafe { BitmapData bmd = frame.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed); byte *ptr; int index = 0; for (int y = 0; y < height; ++y) { ptr = (byte *)bmd.Scan0 + y * bmd.Stride; for (int x = 0; x < width; ++x, ++index) { data[index] = (byte)*ptr; ptr++; } } frame.UnlockBits(bmd); }*/ gc.WriteDataBlocks(data, 8); } public void WriteControl(ushort delay) { WriteControl(delay, -1, false, GifDisposalMethod.NoDisposal); } public void WriteControl(ushort delay, int transparent) { WriteControl(delay, transparent, false, GifDisposalMethod.NoDisposal); } public void WriteControl(ushort delay, int transparent, bool userInput, GifDisposalMethod disposalMethod) { writeControlInternal(stream, delay, transparent, userInput, disposalMethod); } public byte[] GetControl(ushort delay) { return GetControl(delay, -1, false, GifDisposalMethod.NoDisposal); } public byte[] GetControl(ushort delay, int transparent) { return GetControl(delay, transparent, false, GifDisposalMethod.NoDisposal); } public byte[] GetControl(ushort delay, int transparent, bool userInput, GifDisposalMethod disposalMethod) { MemoryStream s = new MemoryStream(); writeControlInternal(s, delay, transparent, userInput, disposalMethod); return s.ToArray(); } private void writeControlInternal(Stream s, ushort delay, int transparent, bool userInput, GifDisposalMethod disposalMethod) { BinaryWriter bw = new BinaryWriter(s); bw.Write((byte)0x21); bw.Write((byte)0xF9); bw.Write((byte)4); byte packed = 0; if (transparent >= 0 && transparent <= 255) { packed |= 1; } if (userInput) { packed |= 2; } packed |= (byte)(((byte)disposalMethod) << 2); bw.Write(packed); bw.Write(delay); if (transparent >= 0 && transparent <= 255) { bw.Write((byte)transparent); } else { bw.Write((byte)0x00); } bw.Write((byte)0x00); } } public enum GifDisposalMethod { NoDisposal = 0, DoNotDispose = 1, RestoreBgColor = 2, RestorePrevious = 3, } public class GifPalette { private Color[] entries; public Color this[int index] { get { return entries[index]; } set { entries[index] = value; } } public GifPalette() { entries = new Color[256]; } } }