image_gif.c

来自「CS架构的多平台的GUI系统」· C语言 代码 · 共 493 行

C
493
字号
/***************************************************************************    begin                : Sun Jul 10 2005    copyright            : (C) 2005 by Alper Akcan    email                : distchx@yahoo.com ***************************************************************************//*************************************************************************** *                                                                         * *   This program is free software; you can redistribute it and/or modify  * *   it under the terms of the GNU Lesser General Public License as        * *   published by the Free Software Foundation; either version 2.1 of the  * *   License, or (at your option) any later version.                       * *                                                                         * ***************************************************************************/#include "xynth_.h"#if defined(IMAGE_GIF)/* this code is heavily based on SDL_image gif source code   www.libsdl.org/projects/SDL_image/ */#define CM_RED		0#define CM_GREEN	1#define CM_BLUE		2#define	MAX_LWZ_BITS		12#define INTERLACE	    	0x40#define LOCALCOLORMAP   	0x80#define	MAXCOLORMAPSIZE		256#define lm_to_uint(a, b)	(((b) << 8) | (a))#define bit_set(byte, bit)	(((byte) & (bit)) == (bit))typedef struct gif_screen_s {	unsigned int width;	unsigned int height;	unsigned char color_map[3][MAXCOLORMAPSIZE];	unsigned int bit_pixel;	unsigned int color_resolution;	unsigned int background;	unsigned int aspect_ratio;	int gray_scale;} gif_screen_t;typedef struct gif89_s {	int transparent;	int delay_time;	int input_flag;	int disposal;} gif89_t;typedef struct gifdata_s {	unsigned char buf[280];	int curbit;	int lastbit;	int done;	int last_byte;	/*	 */	int fresh;	int code_size;	int set_code_size;	int max_code;	int max_code_size;	int firstcode;	int oldcode;	int clear_code;	int end_code;	int table[2][(1 << MAX_LWZ_BITS)];	int stack[(1 << (MAX_LWZ_BITS)) * 2];	int *sp;	/*	 */	int zero_data_block;	/*	 */	gif89_t gif89;	gif_screen_t gif_screen;} gifdata_t;static int s_image_gif_read_file (unsigned char *buf, unsigned int size, FILE *fp){	if (fread(buf, 1, size, fp) < size) {		return -1;	} else {		return 0;	}}static int s_image_gif_get_data_block (FILE *fp, unsigned char *buf, gifdata_t *data){	unsigned char count;	if (s_image_gif_read_file(&count, 1, fp)) {		return -1;	}	data->zero_data_block = count == 0;	if ((count != 0) && s_image_gif_read_file(buf, count, fp)) {		return -1;	}	return count;}static int s_image_gif_do_extension (FILE *fp, int label, gifdata_t *data){	unsigned char buf[256];	switch (label) {		case 0x01:			/* Plain Text Extension */			break;		case 0xff:			/* Application Extension */			break;		case 0xfe:			/* Comment Extension */			while (s_image_gif_get_data_block(fp, (unsigned char *) buf, data) != 0);			return 0;		case 0xf9:			/* Graphic Control Extension */			(void) s_image_gif_get_data_block(fp, (unsigned char *) buf, data);			data->gif89.disposal = (buf[0] >> 2) & 0x7;			data->gif89.input_flag = (buf[0] >> 1) & 0x1;			data->gif89.delay_time = lm_to_uint(buf[1], buf[2]);			if ((buf[0] & 0x1) != 0) {				data->gif89.transparent = buf[3];			}			while (s_image_gif_get_data_block(fp, (unsigned char *) buf, data) != 0);			return 0;		default:			{				char *str = (char *) buf;				sprintf(str, "unknown label (0x%02x)", label);			}			break;	}	while (s_image_gif_get_data_block(fp, (unsigned char *) buf, data) != 0);	return 0;}static int s_image_gif_read_color_map (FILE *fp, int number, unsigned char buffer[3][MAXCOLORMAPSIZE], int *gray){	int i;	int flag;	unsigned char rgb[3];	flag = 1;	for (i = 0; i < number; ++i) {		if (s_image_gif_read_file(rgb, sizeof(rgb), fp)) {			return 1;		}		buffer[CM_RED][i] = rgb[0];		buffer[CM_GREEN][i] = rgb[1];		buffer[CM_BLUE][i] = rgb[2];		flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]);	}	*gray = 0;	return 0;}static int s_image_gif_get_code (FILE *fp, int code_size, int flag, gifdata_t *data){	int i;	int j;	int ret;	unsigned char count;	if (flag) {		data->curbit = 0;		data->lastbit = 0;		data->done = 0;		return 0;	}	if ((data->curbit + code_size) >= data->lastbit) {		if (data->done) {			if (data->curbit >= data->lastbit)				return -1;		}		if (data->last_byte >= 2) { data->buf[0] = data->buf[data->last_byte - 2]; }		if (data->last_byte >= 1) { data->buf[1] = data->buf[data->last_byte - 1]; }		if ((count = s_image_gif_get_data_block(fp, &(data->buf[2]), data)) == 0)			data->done = 1;		data->last_byte = 2 + count;		data->curbit = (data->curbit - data->lastbit) + 16;		data->lastbit = (2 + count) * 8;	}	ret = 0;	for (i = data->curbit, j = 0; j < code_size; ++i, ++j)		ret |= ((data->buf[i / 8] & (1 << (i % 8))) != 0) << j;	data->curbit += code_size;	return ret;}static int s_image_gif_lwz_read_byte (FILE *fp, int flag, int input_code_size, gifdata_t *data){	int i;	int code;	int incode;	if (flag) {		data->set_code_size = input_code_size;		data->code_size = data->set_code_size + 1;		data->clear_code = 1 << data->set_code_size;		data->end_code = data->clear_code + 1;		data->max_code_size = 2 * data->clear_code;		data->max_code = data->clear_code + 2;		s_image_gif_get_code(fp, 0, 1, data);		data->fresh = 1;		for (i = 0; i < data->clear_code; ++i) {			data->table[0][i] = 0;			data->table[1][i] = i;		}		for (; i < (1 << MAX_LWZ_BITS); ++i)			data->table[0][i] = data->table[1][0] = 0;		data->sp = data->stack;		return 0;	} else if (data->fresh) {		data->fresh = 0;		do {			data->firstcode = data->oldcode = s_image_gif_get_code(fp, data->code_size, 0, data);		} while (data->firstcode == data->clear_code);		return data->firstcode;	}	if (data->sp > data->stack)		return *--(data->sp);	while ((code = s_image_gif_get_code(fp, data->code_size, 0, data)) >= 0) {		if (code == data->clear_code) {			for (i = 0; i < data->clear_code; ++i) {				data->table[0][i] = 0;				data->table[1][i] = i;			}			for (; i < (1 << MAX_LWZ_BITS); ++i)				data->table[0][i] = data->table[1][i] = 0;			data->code_size = data->set_code_size + 1;			data->max_code_size = 2 * data->clear_code;			data->max_code = data->clear_code + 2;			data->sp = data->stack;			data->firstcode = data->oldcode = s_image_gif_get_code(fp, data->code_size, 0, data);			return data->firstcode;		} else if (code == data->end_code) {			int count;			unsigned char buf[260];			if (data->zero_data_block)				return -2;			while ((count = s_image_gif_get_data_block(fp, buf, data)) > 0);			if (count != 0) {			}			return -2;		}		incode = code;		if (code >= data->max_code) {			*(data->sp)++ = data->firstcode;			code = data->oldcode;		}		while (code >= data->clear_code) {			*(data->sp)++ = data->table[1][code];			if (code == data->table[0][code]) {			}			code = data->table[0][code];		}		*(data->sp)++ = data->firstcode = data->table[1][code];		if ((code = data->max_code) < (1 << MAX_LWZ_BITS)) {			data->table[0][code] = data->oldcode;			data->table[1][code] = data->firstcode;			++(data->max_code);			if ((data->max_code >= data->max_code_size) &&			    (data->max_code_size < (1 << MAX_LWZ_BITS))) {				data->max_code_size *= 2;				++(data->code_size);			}		}		data->oldcode = incode;		if (data->sp > data->stack)			return *--(data->sp);	}	return code;}static int s_image_gif_read_image (FILE *fp, int len, int height, int cmapSize, unsigned char cmap[3][MAXCOLORMAPSIZE], int gray, int interlace, int ignore, gifdata_t *data, unsigned int *rgba){	int v;	int xpos = 0;	int ypos = 0;	int pass = 0;	unsigned char c;	if (s_image_gif_read_file(&c, 1, fp)) {		debugf(DFAT, "s_image_gif_read_file error");	}        if (s_image_gif_lwz_read_byte(fp, 1, c, data) < 0) {		debugf(DFAT, "s_image_gif_lwz_read_byte error");	}	if (ignore) {		while (s_image_gif_lwz_read_byte(fp, 0, c, data) >= 0);		return 1;	}	while ((v = s_image_gif_lwz_read_byte(fp, 0, c, data)) >= 0) {		*(rgba + ypos * len + xpos) = ((cmap[CM_RED][v] << 0x18) |					       (cmap[CM_GREEN][v] << 0x10) |		                               (cmap[CM_BLUE][v] << 0x08) |		                               ((data->gif89.transparent == v) ? 0xFF : 0x0));		++xpos;		if (xpos == len) {			xpos = 0;			if (interlace) {				switch (pass) {					case 0:					case 1: ypos += 8; break;					case 2: ypos += 4; break;					case 3: ypos += 2; break;				}				if (ypos >= height) {					++pass;					switch (pass) {						case 1: ypos = 4; break;						case 2: ypos = 2; break;						case 3: ypos = 1; break;						default: goto end;					}				}			} else {				++ypos;			}		}		if (ypos >= height)			break;	}end:	return 0;}int s_image_gif_is (char *file){	FILE *fp;	int ret = -1;	char magic[6];		fp = fopen(file, "r");	if (fp == NULL) {		debugf(DFAT, "Could not open file %s", file);	}	fread(magic, 1, sizeof(magic), fp);	if ((strncmp(magic, "GIF", 3) == 0) &&	    ((memcmp(magic + 3, "87a", 3) == 0) ||	     (memcmp(magic + 3, "89a", 3) == 0))) {		 ret = 0;	}	fclose(fp);	return ret;}int s_image_gif (char *file, s_image_t *img){	int ret;	FILE *fp;	int image;	int bit_pixel;	int gray_scale;	char version[4];	unsigned char c;	int image_number;	gifdata_t *gifdata;	int image_count = 0;	unsigned char buf[16];	int use_global_color_map;	unsigned char localcolor_map[3][MAXCOLORMAPSIZE];	s_image_t *tmp;	ret = 0;	image_number = 1;	gifdata = (gifdata_t *) s_malloc(sizeof(gifdata_t));	memset(gifdata, 0, sizeof(gifdata_t));	fp = fopen(file, "r");	if (fp == NULL) {		debugf(DFAT, "Could not open file %s", file);	}	if (s_image_gif_read_file(buf, 6, fp)) {		debugf(DFAT, "s_image_gif_read_file error");	}	if (strncmp((char *) buf, "GIF", 3) != 0) {		debugf(DFAT, "%s is not gif file", file);	}	strncpy(version, (char *) buf + 3, 3);	version[3] = '\0';	if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {		debugf(DFAT, "%s is not gif file", file);	}	gifdata->gif89.transparent = -1;	gifdata->gif89.delay_time = -1;	gifdata->gif89.input_flag = -1;	gifdata->gif89.disposal = 0;	if (s_image_gif_read_file(buf, 7, fp)) {		debugf(DFAT, "s_image_gif_read_file error");	}	gifdata->gif_screen.width = lm_to_uint(buf[0], buf[1]);	gifdata->gif_screen.height = lm_to_uint(buf[2], buf[3]);	gifdata->gif_screen.bit_pixel = 2 << (buf[4] & 0x07);	gifdata->gif_screen.color_resolution = (((buf[4] & 0x70) >> 3) + 1);	gifdata->gif_screen.background = buf[5];	gifdata->gif_screen.aspect_ratio = buf[6];	if (bit_set(buf[4], LOCALCOLORMAP)) {		if (s_image_gif_read_color_map(fp, gifdata->gif_screen.bit_pixel, gifdata->gif_screen.color_map, &gifdata->gif_screen.gray_scale)) {			debugf(DFAT, "s_image_gif_read_color_map error");		}	}	do {		if (s_image_gif_read_file(&c, 1, fp)) {			debugf(DFAT, "s_image_gif_read_file error");		}		if (c == ';') {			if (image_count < image_number) {				break;			}		}		if (c == '!') {			if (s_image_gif_read_file(&c, 1, fp)) {				debugf(DFAT, "s_image_gif_read_file error");			}			s_image_gif_do_extension(fp, c, gifdata);			continue;		}		if (c != ',') {			continue;		}		++image_count;		if (s_image_gif_read_file(buf, 9, fp)) {			debugf(DFAT, "s_image_gif_read_file error");		}		use_global_color_map = !bit_set(buf[8], LOCALCOLORMAP);		bit_pixel = 1 << ((buf[8] & 0x07) + 1);		if (image_count == image_number) {			s_image_init(&tmp);			tmp->x = lm_to_uint(buf[0], buf[1]);			tmp->y = lm_to_uint(buf[2], buf[3]);			tmp->w = lm_to_uint(buf[4], buf[5]);			tmp->h = lm_to_uint(buf[6], buf[7]);			tmp->delay = gifdata->gif89.delay_time * 10;			tmp->rgba = (unsigned int *) s_calloc(1, tmp->w * tmp->h * sizeof(unsigned int));			s_list_add(img->layers, tmp, -1);		}		if (!use_global_color_map) {			if (s_image_gif_read_color_map(fp, bit_pixel, localcolor_map, &gray_scale)) {				debugf(DFAT, "s_image_gif_read_color_map error");			}			image = s_image_gif_read_image(fp, lm_to_uint(buf[4], buf[5]),					       lm_to_uint(buf[6], buf[7]),					       bit_pixel, localcolor_map, gray_scale,					       bit_set(buf[8], INTERLACE),					       image_count != image_number,					       gifdata, tmp->rgba);			if (image == 0) { image_number++; };		} else {			image = s_image_gif_read_image(fp, lm_to_uint(buf[4], buf[5]),					       lm_to_uint(buf[6], buf[7]),					       gifdata->gif_screen.bit_pixel, gifdata->gif_screen.color_map,					       gifdata->gif_screen.gray_scale, bit_set(buf[8], INTERLACE),					       image_count != image_number,					       gifdata, tmp->rgba);			if (image == 0) { image_number++; };		}	} while (1);	fclose(fp);	s_free(gifdata);	return 0;}#elseint s_image_gif_is (char *file){	return -1;}int s_image_gif (char *file, s_image_t *img){	return -1;}#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?