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);
}
}
}
}
|