This is readGIF.c in view mode; [Download] [Up]
/* ** Copyright 1994, Home Pages, Inc. ** ** Please read the file COPYRIGHT for specific information. ** ** Home Pages, Inc. ** 257 Castro St. Suite 219 ** Mountain View, CA 94041 ** ** Phone: 1 415 903 5353 ** Fax: 1 415 903 5345 ** ** EMail: support@homepages.com ** */ /* +-------------------------------------------------------------------+ */ /* | Copyright 1990 - 1994, David Koblas. (koblas@netcom.com) | */ /* | Permission to use, copy, modify, and distribute this software | */ /* | and its documentation for any purpose and without fee is hereby | */ /* | granted, provided that the above copyright notice appear in all | */ /* | copies and that both that copyright notice and this permission | */ /* | notice appear in supporting documentation. This software is | */ /* | provided "as is" without express or implied warranty. | */ /* +-------------------------------------------------------------------+ */ #include <stdio.h> #include <setjmp.h> #include "gif.h" #define TRUE 1 #define FALSE 0 #define MAX_LWZ_BITS 12 #define INTERLACE 0x40 #define LOCALCOLORMAP 0x80 #define BitSet(byte, bit) (((byte) & (bit)) == (bit)) #define ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0) #define MKINT(a,b) (((b)<<8)|(a)) #define NEW(x) ((x *)malloc(sizeof(x))) /*************************************************************************** * * ERROR() -- should not return * INFO_MSG() -- info message, can be ignored * ***************************************************************************/ #if 0 #define INFO_MSG(fmt) pm_message fmt #define ERROR(str) pm_error(str) #else #if 0 #define INFO_MSG(fmt) #define ERROR(str) do { RWSetMsg(str); longjmp(setjmp_buffer, 1); } while(0) #else #define INFO_MSG(fmt) #define ERROR(str) longjmp(setjmp_buffer, 1) #endif #endif /***************************************************************************/ static int readColorMap(FILE *, int, unsigned char [GIF_MAXCOLORS][3]); static int GetDataBlock(FILE *, unsigned char *); static void readImage(FILE *, int, int, int, unsigned char *); static jmp_buf setjmp_buffer; static int verbose = FALSE; static int showComment = FALSE; int GIFTest(char *file) { FILE *fd = fopen(file, "rb"); char buf[10]; int ret = FALSE; if (fd != NULL && ReadOK(fd, buf, 6)) { if ((strncmp(buf, "GIF", 3) == 0) && ((strncmp(buf + 3, "87a", 3) != 0) || (strncmp(buf + 3, "89a", 3) != 0))) ret = TRUE; } fclose(fd); return ret; } GIFStream *GIFReadFP(FILE *fd) { unsigned char buf[256]; unsigned char c; GIFStream *stream; GIFData *cur, **end; GIF89info info; int resetInfo = TRUE; int n; if (fd == NULL) return NULL; if (setjmp(setjmp_buffer)) goto out; if (! ReadOK(fd,buf,6)) ERROR("error reading magic number" ); if (strncmp((char*)buf,"GIF",3) != 0) ERROR("not a GIF file" ); if ((strncmp(buf + 3, "87a", 3) != 0) && (strncmp(buf + 3, "89a", 3) != 0)) ERROR("bad version number, not '87a' or '89a'" ); if (! ReadOK(fd,buf,7)) ERROR("failed to read screen descriptor"); stream = NEW(GIFStream); stream->width = MKINT(buf[0], buf[1]); stream->height = MKINT(buf[2], buf[3]); stream->cmapSize = 2 << (buf[4] & 0x07); stream->colorMapSize = stream->cmapSize; stream->colorResolution = ((int)(buf[4] & 0x70) >> 3) + 1; stream->background = buf[5]; stream->aspectRatio = buf[6]; stream->data = NULL; end = &stream->data; /* ** Global colormap is present. */ if (BitSet(buf[4], LOCALCOLORMAP)) { if (readColorMap(fd, stream->cmapSize, stream->cmapData)) ERROR("unable to get global colormap"); } else { stream->cmapSize = 0; stream->background = -1; } if (stream->aspectRatio != 0 && stream->aspectRatio != 49) { float r; r = ((float) stream->aspectRatio + 15.0) / 64.0; INFO_MSG(("warning - non-square pixels; to fix do a 'pnmscale -%cscale %g'", r < 1.0 ? 'x' : 'y', r < 1.0 ? 1.0 / r : r )); } while (ReadOK(fd, &c, 1) && c != ';') { if (resetInfo) { info.disposal = 0; info.inputFlag = 0; info.delayTime = 0; info.transparent = -1; resetInfo = FALSE; } cur = NULL; if (c == '!') { /* Extension */ if (! ReadOK(fd,&c,1)) ERROR("EOF / read error on extention function code"); if (c == 0xf9) { /* graphic control */ (void) GetDataBlock(fd, buf); info.disposal = (buf[0] >> 2) & 0x7; info.inputFlag = (buf[0] >> 1) & 0x1; info.delayTime = MKINT(buf[1],buf[2]); if (BitSet(buf[0], 0x1)) info.transparent = buf[3]; while (GetDataBlock(fd, buf) != 0) ; } else if (c == 0xfe || c == 0x01) { int len = 0; int size = 256; char *text = NULL; /* ** Comment or Plain Text */ cur = NEW(GIFData); if (c == 0x01) { (void)GetDataBlock(fd, buf); cur->type = gif_text; cur->info = info; cur->x = MKINT(buf[0],buf[1]); cur->y = MKINT(buf[2],buf[3]); cur->width = MKINT(buf[4],buf[5]); cur->height = MKINT(buf[6],buf[7]); cur->data.text.cellWidth = buf[8]; cur->data.text.cellHeight = buf[9]; cur->data.text.fg = buf[10]; cur->data.text.bg = buf[11]; resetInfo = TRUE; } else { cur->type = gif_comment; } text = (char*)malloc(size); while ((n = GetDataBlock(fd, buf)) != 0) { if (n + len >= size) text = (char*)realloc(text, size += 256); memcpy(text + len, buf, n); len += n; } if (c == 0x01) { cur->data.text.len = len; cur->data.text.text = text; } else { cur->data.comment.len = len; cur->data.comment.text = text; } } else { /* ** Unrecogonized extension, consume it. */ while (GetDataBlock(fd, buf) > 0) ; } } else if (c == ',') { if (! ReadOK(fd,buf,9)) ERROR("couldn't read left/top/width/height"); cur = NEW(GIFData); cur->type = gif_image; cur->info = info; cur->x = MKINT(buf[0], buf[1]); cur->y = MKINT(buf[2], buf[3]); cur->width = MKINT(buf[4], buf[5]); cur->height = MKINT(buf[6], buf[7]); cur->data.image.cmapSize = 1 << ((buf[8] & 0x07) + 1); if (BitSet(buf[8], LOCALCOLORMAP)) { if (readColorMap(fd, cur->data.image.cmapSize, cur->data.image.cmapData)) ERROR("unable to get local colormap"); } else { cur->data.image.cmapSize = 0; } cur->data.image.data = (unsigned char *)malloc(cur->width * cur->height); cur->data.image.interlaced = BitSet(buf[8], INTERLACE); readImage(fd, BitSet(buf[8], INTERLACE), cur->width, cur->height, cur->data.image.data); resetInfo = TRUE; } else { INFO_MSG(("bogus character 0x%02x, ignoring", (int)c)); } if (cur != NULL) { *end = cur; end = &cur->next; cur->next = NULL; } } if (c != ';') ERROR("EOF / data stream" ); out: return stream; } GIFStream *GIFRead(char *file) { FILE *fp = fopen(file, "rb"); GIFStream *stream = NULL; if (fp != NULL) { stream = GIFReadFP(fp); fclose(fp); } return stream; } static int readColorMap(FILE *fd, int size, unsigned char data[GIF_MAXCOLORS][3]) { int i; unsigned char rgb[3 * GIF_MAXCOLORS]; unsigned char *cp = rgb; if (! ReadOK(fd, rgb, size * 3)) return TRUE; for (i = 0; i < size; i++) { data[i][0] = *cp++; data[i][1] = *cp++; data[i][2] = *cp++; } return FALSE; } /* ** */ static int ZeroDataBlock = FALSE; static int GetDataBlock(FILE *fd, unsigned char *buf) { unsigned char count; if (! ReadOK(fd,&count,1)) { INFO_MSG(("error in getting DataBlock size")); return -1; } ZeroDataBlock = count == 0; if ((count != 0) && (! ReadOK(fd, buf, count))) { INFO_MSG(("error in reading DataBlock")); return -1; } return count; } /* ** ** */ /* ** Pulled out of nextCode */ static int curbit, lastbit, get_done, last_byte; static int return_clear; /* ** Out of nextLWZ */ static int stack[(1<<(MAX_LWZ_BITS))*2], *sp; static int code_size, set_code_size; static int max_code, max_code_size; static int clear_code, end_code; static void initLWZ(int input_code_size) { static int inited = FALSE; set_code_size = input_code_size; code_size = set_code_size + 1; clear_code = 1 << set_code_size ; end_code = clear_code + 1; max_code_size = 2 * clear_code; max_code = clear_code + 2; curbit = lastbit = 0; last_byte = 2; get_done = FALSE; return_clear = TRUE; sp = stack; } static int nextCode(FILE *fd, int code_size) { static unsigned char buf[280]; static int maskTbl[16] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, }; int i, j, ret, end; if (return_clear) { return_clear = FALSE; return clear_code; } end = curbit + code_size; if (end >= lastbit) { int count; if (get_done) { if (curbit >= lastbit) ERROR("ran off the end of my bits" ); return -1; } buf[0] = buf[last_byte-2]; buf[1] = buf[last_byte-1]; if ((count = GetDataBlock(fd, &buf[2])) == 0) get_done = TRUE; last_byte = 2 + count; curbit = (curbit - lastbit) + 16; lastbit = (2+count)*8 ; end = curbit + code_size; } j = end / 8; i = curbit / 8; if (i == j) ret = buf[i]; else if (i + 1 == j) ret = buf[i] | (buf[i+1] << 8); else ret = buf[i] | (buf[i+1] << 8) | (buf[i+2] << 16); ret = (ret >> (curbit % 8)) & maskTbl[code_size]; curbit += code_size; return ret; } #define readLWZ(fd) ((sp > stack) ? *--sp : nextLWZ(fd)) static int nextLWZ(FILE *fd) { static int table[2][(1<< MAX_LWZ_BITS)]; static int firstcode, oldcode; int code, incode; register int i; while ((code = nextCode(fd, code_size)) >= 0) { if (code == clear_code) { for (i = 0; i < clear_code; ++i) { table[0][i] = 0; table[1][i] = i; } for (; i < (1<<MAX_LWZ_BITS); ++i) table[0][i] = table[1][i] = 0; code_size = set_code_size+1; max_code_size = 2*clear_code; max_code = clear_code+2; sp = stack; do { firstcode = oldcode = nextCode(fd, code_size); } while (firstcode == clear_code); return firstcode; } if (code == end_code) { int count; unsigned char buf[260]; if (ZeroDataBlock) return -2; while ((count = GetDataBlock(fd, buf)) > 0) ; if (count != 0) INFO_MSG(("missing EOD in data stream")); return -2; } incode = code; if (code >= max_code) { *sp++ = firstcode; code = oldcode; } while (code >= clear_code) { *sp++ = table[1][code]; if (code == table[0][code]) ERROR("circular table entry BIG ERROR"); code = table[0][code]; } *sp++ = firstcode = table[1][code]; if ((code = max_code) <(1<<MAX_LWZ_BITS)) { table[0][code] = oldcode; table[1][code] = firstcode; ++max_code; if ((max_code >= max_code_size) && (max_code_size < (1<<MAX_LWZ_BITS))) { max_code_size *= 2; ++code_size; } } oldcode = incode; if (sp > stack) return *--sp; } return code; } static void readImage(FILE *fd, int interlace, int width, int height, unsigned char *data) { unsigned char *dp, c; int v, xpos = 0, ypos = 0, pass = 0; /* ** Initialize the Compression routines */ if (! ReadOK(fd,&c,1)) ERROR("EOF / read error on image data" ); initLWZ(c); if (verbose) INFO_MSG(("reading %d by %d%s GIF image", width, height, interlace ? " interlaced" : "")); if (interlace) { int i; int pass = 0, step = 8; for (i = 0; i < height; i++) { dp = &data[width * ypos]; for (xpos = 0; xpos < width; xpos++) { if ((v = readLWZ(fd)) < 0) goto fini; *dp++ = v; } if ((ypos += step) >= height) { do { if (pass++ > 0) step /= 2; ypos = step / 2; } while (ypos > height); } } } else { dp = data; for (ypos = 0; ypos < height; ypos++) { for (xpos = 0; xpos < width; xpos++) { if ((v = readLWZ(fd)) < 0) goto fini; *dp++ = v; } } } fini: if (readLWZ(fd) >= 0) INFO_MSG(("too much input data, ignoring extra...")); return; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.