Chinaunix首页 | 论坛 | 博客
  • 博客访问: 908317
  • 博文数量: 201
  • 博客积分: 8078
  • 博客等级: 中将
  • 技术积分: 2162
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-20 17:22
文章分类

全部博文(201)

文章存档

2013年(3)

2012年(11)

2011年(34)

2010年(25)

2009年(51)

2008年(77)

分类: WINDOWS

2010-03-29 01:06:17

using System;
using System.IO;
using System.Text;

namespace HelloWorld
{
    struct BITMAPFILEHEADER {
        public ushort bfType;
        public uint bfSize;
        public uint bfReserved;
        public uint bfOffBits;
    };

    struct BITMAPINFOHEADER {
        public uint biSize;
        public int biWidth;
        public int biHeight;
        public ushort biPlanes;
        public ushort biBitCount;
        public uint biCompression;
        public uint biSizeImage;
        public int biXPelsPerMeter;
        public int biYPelsPerMeter;
        public uint biClrUsed;
        public uint biClrImportant;
    };

    struct GIFSCRDESC {
        public ushort width;
        public ushort depth;
        public byte flags;
        public byte backGround;
        public byte aspect;
    };

    struct GIFIMAGE {
        public ushort left;
        public ushort top;
        public ushort width;
        public ushort depth;
        public byte flags;
        /*
         struct LocalFlag{
         unsigned palBits: 3;
         unsigned reserved: 2;
         unsigned sortFlag: 1;
         unsigned interlace: 1;
         unsigned localPal: 1;
         }__attribute__((packed))localFlag;
         */

    };

    class GifImage {
        int bitcnt = 9;
        ushort dicode = 256 + 2;
        ushort[] dictbl = new ushort[256 * 4096];

        static uint[] test_mask = {
            1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80,
            0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000,
            0x10000, 0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000,
            0x1000000, 0x2000000, 0x4000000, 0x8000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000
        };

        static uint[] dictbltest = new uint[32 * 1024];

        void restart()
        {
            bitcnt = 9;
            dicode = (256 + 2);
            Array.Clear(dictbltest, 0, dictbltest.Length);
        }

        int find(int prefix, int code)
        {
            int key = (prefix << 8) | code;
            if ((dictbltest[key >> 5] &
                        test_mask[key & 0x1F]) > 0)
                return dictbl[key];
            return -1;
        }


        int update(int prefix, int code)
        {
            int key = (prefix << 8) | code;
            dictbltest[key >> 5] |= test_mask[key & 0x1F];
            dictbl[key] = dicode++;
            return dicode;
        }


        int outbitcnt = 0;
        int outbitbuff = 0;

        int outcnt = 0;
        byte[] outbuff = new byte[8192 + 4];

        void output(int code, Stream file)
        {
            int i;
            int mask = (1 << bitcnt) - 1;

            outbitbuff |= ((code & mask) << outbitcnt);
            outbitcnt += bitcnt;

            while (outbitcnt >= 8) {
                byte outch = (byte)(outbitbuff & 0xFF);
                outbuff[outcnt++] = outch;
                outbitbuff >>= 8;
                outbitcnt -= 8;
            }

            if (outcnt >= 8192) {
                for (i = 0; i + 255 <= outcnt; i += 255) {
                    file.WriteByte(0xFF);
                    file.Write(outbuff, i, 255);
                }
                outcnt -= i;
                Array.Copy(outbuff, i, outbuff, 0, outcnt);
            }

            if (mask < dicode){
                ++bitcnt;
            }
        }

        void finish(int code, Stream file)
        {
            int i;
            output(code, file);
            output(257, file);

            if (outbitcnt > 0) {
                byte outch = (byte)(outbitbuff & 0xFF);
                outbuff[outcnt++] = outch;
            }
            
            int cpcnt = 0;
            for (i = 0; i < outcnt; i += cpcnt) {
                cpcnt = 0xFF;
                if (cpcnt + i > outcnt)
                    cpcnt = outcnt - i;
                file.WriteByte((byte)cpcnt);
                file.Write(outbuff, i, cpcnt);
            }

            file.WriteByte(0);
            outcnt = 0;
        }

        byte GifLocalFlags(bool localPal, int palBits, bool interlace, bool sortFlag)
        {
            int flags = 0;
            flags = (palBits & 0x7);
            if (sortFlag)
                flags |= 0x20;
            if (interlace)
                flags |= 0x40;
            if (localPal)
                flags |= 0x80;
            return (byte)flags;
        }

        byte GifGlobalFlags(int palBits, bool sortFlags, int colorRes, bool globalPal)
        {
            /*
             struct GlobalFlag{
             unsigned palBits: 3;
             unsigned sortFlag: 1;
             unsigned colorRes: 3;
             unsigned globalPal: 1;
             }__attribute__((packed))globalFlag;
             */


            int flags = 0;
            flags |= (palBits & 0x07);
            if (sortFlags)
                flags |= 0x08;
            flags |= ((colorRes & 0x07) << 4);
            if (globalPal)
                flags |= 0x8;
            return (byte)flags;
        }

        void WriteGifFileHeader(Stream outStream)
        {
            GIFSCRDESC desc;
            byte[] data = Encoding.ASCII.GetBytes("GIF89a");
            outStream.Write(data, 0, data.Length);

            desc.width = 1280;
            desc.depth = 800;
            desc.flags = GifGlobalFlags(7, false, 0, false);
            desc.backGround = 0;
            desc.aspect = 0;

            data = BitConverter.GetBytes(desc.width);
            outStream.Write(data, 0, data.Length);

            data = BitConverter.GetBytes(desc.depth);
            outStream.Write(data, 0, data.Length);

            outStream.WriteByte(desc.flags);
            outStream.WriteByte(desc.backGround);
            outStream.WriteByte(desc.aspect);
        }

        BITMAPFILEHEADER ReadBitmapFileHeader(Stream inStream)
        {
            BITMAPFILEHEADER header;
            byte[] data = new byte[14];
            inStream.Read(data, 0, data.Length);
            header.bfType = BitConverter.ToUInt16(data, 0);
            header.bfSize = BitConverter.ToUInt32(data, 2);
            header.bfReserved = BitConverter.ToUInt32(data, 6);
            header.bfOffBits = BitConverter.ToUInt32(data, 10);
            Console.WriteLine("bfType: {0} ", header.bfType);
            Console.WriteLine("bfSize: {0} ", header.bfSize);
            Console.WriteLine("bfOffBits: {0} ", header.bfOffBits);
            return header;
        }

        BITMAPINFOHEADER ReadBitmapInfoHeader(Stream inStream)
        {
            BITMAPINFOHEADER header;
            byte[] data = new byte[40];
            inStream.Read(data, 0, data.Length);
            header.biSize = BitConverter.ToUInt32(data, 0);
            Console.WriteLine("biSize: {0}", header.biSize);
            header.biWidth = BitConverter.ToInt32(data, 4);
            header.biHeight = BitConverter.ToInt32(data, 8);
            header.biPlanes = BitConverter.ToUInt16(data, 12);
            header.biBitCount = BitConverter.ToUInt16(data, 14);
            Console.WriteLine("biBitCount: {0}", header.biBitCount);
            header.biCompression = BitConverter.ToUInt32(data, 16);
            header.biSizeImage = BitConverter.ToUInt32(data, 20);
            header.biXPelsPerMeter = BitConverter.ToInt32(data, 24);
            header.biYPelsPerMeter = BitConverter.ToInt32(data, 28);
            header.biClrUsed = BitConverter.ToUInt32(data, 32);
            header.biClrImportant = BitConverter.ToUInt32(data, 36);
            return header;
        }

        public int convert(string pathin, string pathout)
        {
            int i, j;
            byte[] buffer = new byte[8192];

            int prefix = -1;

            Stream outStream = File.OpenWrite(pathout);

            WriteGifFileHeader(outStream);

            byte[] lcb = {0x21, 0xFF, 0x0B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x03, 0x01, 0x00, 0x00, 0x00};
            byte[] netscape = Encoding.ASCII.GetBytes("NETSCAPE2.0");
            Array.Copy(netscape, 0, lcb, 3, netscape.Length);
            outStream.Write(lcb, 0, lcb.Length);

            byte[] gcb = {0x21, 0xF9, 0x04, 0x0B, 0x70, 0x00, 0x00, 0x00};
            outStream.Write(gcb, 0, gcb.Length);

            Stream inStream = File.OpenRead(pathin);
            BITMAPFILEHEADER bmfHeader = ReadBitmapFileHeader(inStream);
            BITMAPINFOHEADER bmiHeader = ReadBitmapInfoHeader(inStream);
            if (bmiHeader.biBitCount != 8) {
                System.Console.WriteLine("BITMAPINFOHEADER: {0}", bmiHeader.biBitCount);
                return 0;
            }

            System.Console.WriteLine("BITMAPINFOHEADER: {0}", bmiHeader.biHeight);

            outStream.WriteByte(0x2c);
            GIFIMAGE gifImage;
            gifImage.left = 0;
            gifImage.top = 0;
            gifImage.width = (ushort)bmiHeader.biWidth;
            gifImage.depth = (ushort)(bmiHeader.biHeight < 0? -bmiHeader.biHeight: bmiHeader.biHeight);
            gifImage.flags = GifLocalFlags(true, 7, false, false);

            byte[] data = BitConverter.GetBytes(gifImage.left);
            outStream.Write(data, 0, data.Length);

            data = BitConverter.GetBytes(gifImage.top);
            outStream.Write(data, 0, data.Length);

            data = BitConverter.GetBytes(gifImage.width);
            outStream.Write(data, 0, data.Length);

            data = BitConverter.GetBytes(gifImage.depth);
            outStream.Write(data, 0, data.Length);
            outStream.WriteByte(gifImage.flags);

            byte[] color_table = new byte[4 * 256];
            inStream.Read(color_table, 0, color_table.Length);
            for (i = 0; i < 4 * 256; i += 4) {
                 outStream.WriteByte(color_table[i + 2]);
                 outStream.WriteByte(color_table[i + 1]);
                 outStream.WriteByte(color_table[i + 0]);
            }
            outStream.WriteByte(0x08);

            prefix = -1;
            restart();
            output(256, outStream);

            byte[] line_data;
            int line = 0, depth = 0, doff = 0;
            if (bmiHeader.biHeight < 0) {
                line = (bmiHeader.biWidth + 3) & ~0x03;
                depth = - bmiHeader.biHeight;
                doff = (int)bmfHeader.bfOffBits;
                line_data = new byte[line];
            } else {
                line = -((bmiHeader.biWidth + 3) & ~0x03);
                depth = bmiHeader.biHeight;
                doff = ((int)bmfHeader.bfOffBits) - (depth * line) + line;
                line_data = new byte[-line];
            }

            for (i = 0; i < depth; i++) {
                inStream.Seek(doff, SeekOrigin.Begin);
                inStream.Read(line_data, 0, line_data.Length);
                for (j = 0; j < bmiHeader.biWidth; j++) {
                    int code = line_data[j] & 0xFF;
                    if (prefix == -1){
                        prefix = code;
                        continue;
                    }
                    int prefix1 = find(prefix, code);
                    if (prefix1 != -1){
                        prefix = prefix1;
                        continue;
                    }
                    output(prefix, outStream);
                    if (update(prefix, code) < 4096){
                        prefix = code;
                        continue;
                    }
                    output(256, outStream);
                    prefix = code;
                    restart();
                }
                doff += line;
            }

            finish(prefix, outStream);
            outStream.WriteByte(0x3b);
            outStream.Close();
            return 0;
        }
    }

    class MainClass
    {        
        public static void Main (string[] args)
        {
            foreach (string path in args) {
                GifImage image = new GifImage();
                image.convert(path, path + ".gif");    
                System.Console.WriteLine("convert {0} ", path);
            }            
        }
    }
}


阅读(958) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~