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

全部博文(201)

文章存档

2013年(3)

2012年(11)

2011年(34)

2010年(25)

2009年(51)

2008年(77)

分类: WINDOWS

2009-09-20 14:25:35


#include 
#include 
#include 
#include 
#include 

#define X(shift) (1 << (shift))
static int test_mask[32] = {
	X(0x00), X(0x01), X(0x02), X(0x03), X(0x04), X(0x05), X(0x06), X(0x07),
	X(0x08), X(0x09), X(0x0a), X(0x0b), X(0x0c), X(0x0d), X(0x0e), X(0x0f),
	X(0x10), X(0x11), X(0x12), X(0x13), X(0x14), X(0x15), X(0x16), X(0x17),
	X(0x18), X(0x19), X(0x1a), X(0x1b), X(0x1c), X(0x1d), X(0x1e), X(0x1f),
};

struct lzwc_ctx {
	int lc_prefix;
	size_t lc_bpp;
	size_t lc_bitcnt;
	size_t lc_dicode;
	size_t lc_testbl[4096 * 256 / sizeof(size_t) / 8];
	size_t lc_dictbl[4096 * 256];

	size_t lc_outcnt;
	char lc_outbuff[8192 + 4];

	size_t lc_outbit_cnt;
	uint32_t lc_outbit_buff;
};
inline void lzwc_clear(struct lzwc_ctx * ctxp, FILE * fp);

inline void lzwc_restart(struct lzwc_ctx * ctxp)
{
	ctxp->lc_dicode = (1 << ctxp->lc_bpp) + 2;
	ctxp->lc_bitcnt = (ctxp->lc_bpp + 1);
	if (ctxp->lc_dicode >= (1 << ctxp->lc_bitcnt))
		ctxp->lc_bitcnt++;
	memset(ctxp->lc_testbl, 0, sizeof(ctxp->lc_testbl));
}

inline void lzwc_init(struct lzwc_ctx * ctxp, int bpp)
{
	memset(ctxp, 0, sizeof(struct lzwc_ctx));
	ctxp->lc_bpp = bpp;
	ctxp->lc_prefix = -1;
	lzwc_restart(ctxp);
   	lzwc_clear(ctxp, NULL);
}

inline int lzwc_find(struct lzwc_ctx * ctxp, int prefix, int code)
{
	int key = (prefix << 8) | code;
	assert (code < (1 << ctxp->lc_bpp));
	if (ctxp->lc_testbl[key >> 5] &
			test_mask[key & 0x1F])
		return ctxp->lc_dictbl[key];
	return -1;
}

inline int lzwc_update(struct lzwc_ctx * ctxp, int prefix, int code)
{
	int key = (prefix << 8) | code;
	ctxp->lc_testbl[key >> 5] |= test_mask[key & 0x1F];
	ctxp->lc_dictbl[key] = ctxp->lc_dicode++;
	return ctxp->lc_dicode;
}

inline void lzwc_output(struct lzwc_ctx * ctxp, size_t code, FILE *fp)
{
	int i;
	char flag = 0xff;
	size_t mask = (1 << ctxp->lc_bitcnt) - 1;

	ctxp->lc_outbit_buff |= ((code & mask) << ctxp->lc_outbit_cnt);
	ctxp->lc_outbit_cnt += ctxp->lc_bitcnt;

	while (ctxp->lc_outbit_cnt >= 8) {
		char outch = (ctxp->lc_outbit_buff & 0xFF);
		ctxp->lc_outbuff[ctxp->lc_outcnt++] = outch;
		ctxp->lc_outbit_buff >>= 8;
		ctxp->lc_outbit_cnt -= 8;
	}
	if (ctxp->lc_outcnt >= 8192) {
		char * s = ctxp->lc_outbuff;
		while (ctxp->lc_outcnt >= 255) {
		   	fwrite(&flag, 1, 1, fp);
		   	fwrite(s, 1, 255, fp);
		   	ctxp->lc_outcnt -= 255;
			s += 255;
		}
		memmove(ctxp->lc_outbuff, s, ctxp->lc_outcnt);
	}
	if (mask < ctxp->lc_dicode) {
		++ctxp->lc_bitcnt;
	}
}

inline void lzwc_clear(struct lzwc_ctx * ctxp, FILE * fp)
{
	int clear = (1 << ctxp->lc_bpp);
	lzwc_output(ctxp, clear, fp);
}

inline void lzwc_finish(struct lzwc_ctx * ctxp, FILE *fp)
{
	int fin_code = (1 << ctxp->lc_bpp) + 1;
	lzwc_output(ctxp, ctxp->lc_prefix, fp);
	lzwc_output(ctxp, fin_code, fp);

    if (ctxp->lc_outbit_cnt > 0) {
        char outch = (ctxp->lc_outbit_buff & 0xFF);
		ctxp->lc_outbuff[ctxp->lc_outcnt] = outch;
		ctxp->lc_outcnt++;
    }
	
	char flag = 255;
	char * s = ctxp->lc_outbuff;
   	while (ctxp->lc_outcnt >= 255) {
	   	fwrite(&flag, 1, 1, fp);
	   	fwrite(s, 1, 255, fp);
	   	ctxp->lc_outcnt -= 255;
	   	s += 255;
   	}

	if (ctxp->lc_outcnt > 0) {
	   	flag = ctxp->lc_outcnt;
	   	fwrite(&flag, 1, 1, fp);
	   	fwrite(s, 1, ctxp->lc_outcnt, fp);
	}

	flag = 0;
	fwrite(&flag, 1, 1, fp);
}

inline void lzwc_encode(struct lzwc_ctx * ctxp,
	   	const void * buf, int count, int bpp, FILE * fpo)
{
	int code = 0;
	int bitcnt = 0;
	uint32_t bitvals = 0;
	uint32_t bitmask = (1 << bpp) - 1;
	const uint8_t * bitsrc = (const uint8_t *) buf;

	assert (bpp <= ctxp->lc_bpp);
	while (count > 0) {
		if (bitcnt < bpp) {
			bitvals = ((bitvals << 8) | *bitsrc++);
			bitcnt += 8;
		}
		count--;
		bitcnt -= bpp;
		code = (bitvals >> bitcnt) & bitmask;
		if (ctxp->lc_prefix == -1) {
			ctxp->lc_prefix = code;
			continue;
		}
		int prefix1 = lzwc_find(ctxp, ctxp->lc_prefix, code);
		if (prefix1 != -1) {
		   	assert(prefix1 <= ctxp->lc_dicode);
			ctxp->lc_prefix = prefix1;
			continue;
		}
		lzwc_output(ctxp, ctxp->lc_prefix, fpo);
		if (lzwc_update(ctxp, ctxp->lc_prefix, code) < 4096) {
			ctxp->lc_prefix = code;
			continue;
		}
		lzwc_clear(ctxp, fpo);
		ctxp->lc_prefix = code;
		lzwc_restart(ctxp);
	}
}

typedef struct
{
	uint16_t bfType;
	uint32_t bfSize;
	uint16_t bfReserved1;
	uint16_t bfReserved2;
	uint32_t bfOffBits;
}__attribute__((packed)) BITMAPFILEHEADER;

typedef struct
{
	uint32_t biSize;
	int32_t biWidth;
	int32_t biHeight;
	uint16_t biPlanes;
	uint16_t biBitCount;
	uint32_t biCompression;
	uint32_t biSizeImage;
	int32_t biXPelsPerMeter;
	int32_t biYPelsPerMeter;
	uint32_t biClrUsed;
	uint32_t biClrImportant;
} BITMAPINFOHEADER;

typedef struct gifScrDesc{
	uint16_t width;
	uint16_t depth;
	struct GlobalFlag{
		unsigned palBits: 3;
		unsigned sortFlag: 1;
		unsigned colorRes: 3;
		unsigned globalPal: 1;
	}__attribute__((packed))globalFlag;
	uint8_t backGround;
	uint8_t aspect;
}__attribute__((packed))GIFSCRDESC;

typedef struct gifImage{
	uint16_t left;
	uint16_t top;
	uint16_t width;
	uint16_t depth;
	struct LocalFlag{
		unsigned palBits: 3;
		unsigned reserved: 2;
		unsigned sortFlag: 1;
		unsigned interlace: 1;
		unsigned localPal: 1;
	}__attribute__((packed))localFlag;
}__attribute__((packed))GIFIMAGE;

static struct lzwc_ctx __lzwc_ctx;

const char * fncpy(char * dst, size_t len, const char * src, const char * ext)
{
	char ign = 0;
	size_t l = len;
	char * s = dst;
	char * lastchar = &ign;

	strncpy(dst, src, len);
	while (l > 0 && *s != 0) {
		if (*s == '/' || 
				*s == '.' ||
				*s == '\\')
			lastchar = s;
		s++;
		l--;
	}

	if (*lastchar == '.')
		*lastchar = '\0';
	strncat(dst, ext, len);
	return dst;
}

int bitmap2gif(const char * bitmap, const char * gif)
{
	int u, i;
	int count;
	int width, height;
	int width3, total;

	char flag = 0;
	GIFSCRDESC desc;
	GIFIMAGE   gifImage;
	BITMAPFILEHEADER bfhdr;
	BITMAPINFOHEADER bihdr;
	printf("bitmap %s, gif %s\n", bitmap, gif);

	FILE * fin = fopen(bitmap, "rb");
	assert(fin != NULL);
	count = fread(&bfhdr, 1, sizeof(bfhdr), fin);
	assert(count == sizeof(bfhdr));
	count = fread(&bihdr, 1, sizeof(bihdr), fin);
	assert(count == sizeof(bihdr));
	assert(memcmp("BM", &bfhdr.bfType, 2) == 0);
	assert(bihdr.biBitCount <= 8);

	width = bihdr.biWidth;
	width3 = ((width * bihdr.biBitCount / 8)  + 3) & ~0x03;
	height = bihdr.biHeight < 0? -bihdr.biHeight: bihdr.biHeight;
	total  = height * width3;

	printf("biWidth: %d\n", bihdr.biWidth);
	printf("biHeight: %d\n", bihdr.biHeight);
	printf("biBitCount: %d\n", bihdr.biBitCount);
	printf("biClrUsed: %d\n", bihdr.biClrUsed);
	printf("biClrImportant: %d\n", bihdr.biClrImportant);
	printf("bfOffBits: %d\n", bfhdr.bfOffBits);
	printf("HeaderSize: %d\n", sizeof(bihdr) + sizeof(bfhdr));

	char planes[4 * 256];
	count = bfhdr.bfOffBits - sizeof(bihdr) - sizeof(bfhdr); 
	assert(count > 0);
	fread(planes, 1, count, fin);
	char * buf = (char *)malloc(total);
	fread(buf, 1, total, fin);
	assert(buf != NULL);

	FILE * fout = fopen(gif, "wb");
	assert(fout != NULL);
	fwrite("GIF89a", 1, 6, fout);
	desc.width = width;
	desc.depth = height;
	desc.aspect = 0;
	desc.globalFlag.palBits = (bihdr.biBitCount - 1);
	desc.globalFlag.sortFlag = 0;
	desc.globalFlag.colorRes = 0;
	desc.globalFlag.globalPal = 1;
	assert(sizeof(desc) == 7);
	fwrite(&desc, 1, 7, fout);

	char *color_start = planes;
	for (u = 0; u < (1 << bihdr.biBitCount); u++) {
		char color[3];
		color[2] = *color_start++;
		color[1] = *color_start++;
		color[0] = *color_start++;
		fwrite(color, 1, 3, fout);
		color_start++;
	}

#if 0
	/* application control block */
	char acb[] = {
		0x21, 0xFF, 0x0B, 'N', 'E', 'T', 'S', 'C', 'A', 'P', 'E',
		'2', '.', '0', 0x03, 0x01, 0x00, 0x00, 0x00
	};
	fwrite(acb, 1, sizeof(acb), fout);

	/* graphics control block */
	char gcb[] = {0x21, 0xf9, 0x04, 0x08, 0x7f, 0x00, 0x1f, 0x00};
	fwrite(gcb, 1, sizeof(gcb), fout);

	/* text control block */
	char tcb[] = {
		0x21, 0x01, 0x0c, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00,
		0x10, 0x08, 0x00, 0x15, 0x03,  'k',  'b',  'c', 0x00
	};
	fwrite(tcb, 1, sizeof(tcb), fout);
#endif

	flag = 0x2c;
	fwrite(&flag, 1, 1, fout);

	gifImage.left = 0;
	gifImage.top  = 0;
	gifImage.width = width;
	gifImage.depth = height;
	gifImage.localFlag.localPal = 0;
	gifImage.localFlag.palBits = 0;
	gifImage.localFlag.interlace = 0;
	gifImage.localFlag.sortFlag = 0;
	gifImage.localFlag.reserved = 0;
	assert(9 == sizeof(gifImage));
	fwrite(&gifImage, 1, sizeof(gifImage), fout);

	flag = bihdr.biBitCount;
	flag = (flag > 1)? flag: 2;
	fwrite(&flag, 1, 1, fout);

	int pixel_count = 0;
	int bitcount = bihdr.biBitCount;
	if (height == bihdr.biHeight) {
		lzwc_init(&__lzwc_ctx, flag);
		const char * bitline = &buf[total - width3];
		for (i = 0; i < height; i++) {
			lzwc_encode(&__lzwc_ctx, bitline, width, bitcount, fout);
			pixel_count += width;
			bitline -= width3;
		}
		lzwc_finish(&__lzwc_ctx, fout);
	} else {
		lzwc_init(&__lzwc_ctx, flag);
		const char * bitline = buf;
		for (i = 0; i < height; i++) {
			lzwc_encode(&__lzwc_ctx, bitline, width, bitcount, fout);
			pixel_count += width;
			bitline += width3;
		}
		lzwc_finish(&__lzwc_ctx, fout);
	}
	printf("ftell %lu, total %lu, pixel count %d\n",
		   	ftell(fout), total, pixel_count);

	flag = 0x3b;
	fwrite(&flag, 1, 1, fout);
	free(buf);
	fclose(fout);
	fclose(fin);
	return 0;
}

int main(int argc, char *argv[])
{
	int i;
	char buf[1024];
	for (i = 1; i < argc; i ++) {
		fncpy(buf, sizeof(buf), argv[i], ".gif");
		if (strncmp(buf, argv[i], sizeof(buf)))
			bitmap2gif(argv[i], buf);
	}
	return 0;
}

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