/***************************************************************** * flgifr.c: FBM Release 1.0 25-Feb-90 Michael Mauldin * * Modifications to GIFTORLE are Copyright (C) 1989,1990 by Michael * Mauldin. Permission is granted to use this file in whole or in * part for any purpose, educational, recreational or commercial, * provided that this copyright notice is retained unchanged. * This software is available to all free of charge by anonymous * FTP and in the UUNET archives. * * Derived from 'giftorle', written by David Koblas * * +------------------------------------------------------------------+ * | Copyright 1989, David Koblas. | * | You may copy this file in whole or in part as long as you | * | don't try to make money off it, or pretend that you wrote it. | * +------------------------------------------------------------------+ * * CONTENTS * read_gif (image, stream, mstr, mlen) * * EDITLOG * LastEditDate = Mon Jun 25 00:09:49 1990 - Michael Mauldin * LastFileName = /usr2/mlm/src/misc/fbm/flgifc.c * * HISTORY * 25-Jun-90 Michael Mauldin (mlm@cs.cmu.edu) Carnegie Mellon * Package for Release 1.0 * * 20-Jun-89 Michael Mauldin (mlm) at Carnegie Mellon University * Bug fix (version 0.95) from David Koblas * * 26-Apr-89 Michael Mauldin (mlm) at Carnegie Mellon University * Beta release (version 0.91) mlm@cs.cmu.edu * * 19-Feb-89 Michael Mauldin (mlm) at Carnegie Mellon University * Changed name to flgifr from flgif (since there is now an flgifw) * * 13-Feb-89 Michael Mauldin (mlm) at Carnegie Mellon University * Modified from gif2rle program Copyright 1989 by David Koblas. * Converted to produce FBM image format in memory. * *****************************************************************/ # include # include "fbm.h" #define MAXCOLORMAPSIZE 256 #define TRUE 1 #define FALSE 0 #define BAD 0 #define OK 1 #define MAX_LWZ_BITS 12 #define ReadOK(file,buffer,len) (fread(buffer,len,1,file)!=0) /* * Hacknote: The following two macros were originally written as * while(1){fprintf(...); return(...);} * This caused a compiler warning about the ';' statement not being * reached when called as EasyFail(string,num); * * Using the C ',' operator, the macros can be replaced by a single * function call...note the extra set of parentheses to force the * correct interpretation of the ',' Fuzzy 20-Jun-90 */ #define EasyFail(str,status) return((fprintf (stderr,str), status)) #define HardFail(str,status) exit ((fprintf(stderr,str), status)) #define LM_to_uint(a,b) (((b)<<8)|(a)) #ifndef lint static char *fbmid = "$FBM flgifr.c <1.0> 25-Jun-90 (C) 1989,1990 by Michael Mauldin, source \ code available free from MLM@CS.CMU.EDU and from UUNET archives$"; #endif read_gif (image, fd, mstr, mlen) FBM *image; FILE *fd; char *mstr; int mlen; { unsigned char buf[16]; unsigned char c; int use_global_colormap; int bit_pixel; int count = 0; int rows, cols, rowlen, depth, colors; /* Read magic number 'GIF87a' */ buf[0] = NEXTMCH (fd, mstr, mlen) & 0xff; buf[1] = NEXTMCH (fd, mstr, mlen) & 0xff; buf[2] = NEXTMCH (fd, mstr, mlen) & 0xff; buf[3] = NEXTMCH (fd, mstr, mlen) & 0xff; buf[4] = NEXTMCH (fd, mstr, mlen) & 0xff; buf[5] = NEXTMCH (fd, mstr, mlen) & 0xff; buf[6] = 0; if (strcmp (buf, GIF_MAGIC) != 0) EasyFail("bad magic number (version mismatch?)\n", BAD); if (!ReadOK (fd, buf, 7)) EasyFail("error reading screen descriptor\n", BAD); /* Read image data */ image->hdr.cols = cols = LM_to_uint(buf[0], buf[1]); image->hdr.rows = rows = LM_to_uint(buf[2], buf[3]); image->hdr.planes = 1; image->hdr.bits = depth = (buf[4] & 0x07) + 1; image->hdr.physbits = 8; /* Pad to even byte */ if (depth == 1) { image->hdr.rowlen = rowlen = 16 * ((cols + 15) / 16); } else { image->hdr.rowlen = rowlen = 2 * ((cols + 1) / 2); } image->hdr.plnlen = rowlen * rows; colors = 1 << depth; image->hdr.clrlen = 3 * colors; image->hdr.title[0] = '\0'; image->hdr.credits[0] = '\0'; /* Try to guess aspect ratio */ if (cols == 320 && rows == 200) { image->hdr.aspect = 1.2; } else if (cols == 320 && rows == 175) { image->hdr.aspect = 1.2; } else if (cols == 320 && rows == 400) { image->hdr.aspect = 0.6; } else if (cols == 320 && rows == 350) { image->hdr.aspect = 0.6; } else if (cols == 640 && rows == 200) { image->hdr.aspect = 2.4; } else if (cols == 640 && rows == 175) { image->hdr.aspect = 2.4; } else if (cols == 640 && rows == 400) { image->hdr.aspect = 1.2; } else if (cols == 640 && rows == 350) { image->hdr.aspect = 1.2; } else { image->hdr.aspect = 1.0; } # ifdef DEBUG fprintf (stderr, "\nImage file header:\n\n"); fprintf (stderr, "cols %d\n", image->hdr.cols); fprintf (stderr, "rows %d\n", image->hdr.rows); fprintf (stderr, "planes %d\n", image->hdr.planes); fprintf (stderr, "bits %d\n", image->hdr.bits); fprintf (stderr, "physbits %d\n", image->hdr.physbits); fprintf (stderr, "rowlen %d\n", image->hdr.rowlen); fprintf (stderr, "plnlen %d\n", image->hdr.plnlen); fprintf (stderr, "clrlen %d\n", image->hdr.clrlen); fprintf (stderr, "aspect %1.3lf\n", image->hdr.aspect); fprintf (stderr, "title '%s'\n", image->hdr.title); fprintf (stderr, "credits '%s'\n", image->hdr.credits); # endif /* Allocate image */ alloc_fbm (image); /* Read colormap if given */ if ((buf[4] & 0x80) == 0x80) { if (ReadColorMap (fd, colors, image->cm) == BAD) return (BAD); } while (1) { if (!ReadOK (fd, &c, 1)) EasyFail("No image data -- EOF\n", BAD); if (c == ';') return OK; if (c == '!') { if (!ReadOK (fd, &c, 1)) EasyFail("No extention function code -- EOF\n", BAD); if (IgnoreExtention(fd) == BAD) return (BAD); } if (c != ',') { fprintf(stderr, "Bogus character ignoring '%c'\n", c); continue; } if (count == 1) HardFail("This file contains more than one image! FAILING\n", 1); count++; if (!ReadOK (fd, buf, 9)) EasyFail("Couldn't read left/top/width/height\n", TRUE); # ifdef DEBUG fprintf (stderr, "Image description: "); for (i=0; i<9; i++) fprintf (stderr, "%02x", buf[i]); fprintf (stderr, "\n"); # endif if ((buf[8] & 0x80) == 0x80) use_global_colormap = FALSE; else use_global_colormap = TRUE; bit_pixel = 2 << (buf[8] & 0x07); if (!use_global_colormap && bit_pixel > colors) { HardFail ("Local colormap has more colors than global!\n", BAD); } if (!use_global_colormap) { fprintf (stderr, "Overriding global colormap (%d) with local (%d)\n", colors, bit_pixel); colors = bit_pixel; image->hdr.clrlen = 3 * colors; if (ReadColorMap(fd, colors, image->cm) == BAD) return BAD; } fprintf (stderr, "Reading GIF image [%dx%d], %d bits", image->hdr.cols, image->hdr.rows, image->hdr.bits); if (image->hdr.clrlen > 0) { fprintf (stderr, ", %d colors", image->hdr.clrlen / 3); } else if (image->hdr.bits > 1) { fprintf (stderr, ", grayscale"); } if ((buf[8] & 0x40) == 0x40) { fprintf (stderr, ", interlaced"); } fprintf (stderr, "\n"); if ((buf[8] & 0x40) == 0x40) { if (ReadInterlaced(fd, LM_to_uint(buf[4],buf[5]), LM_to_uint(buf[6],buf[7]), image->bm, rowlen) == BAD) return BAD; } else { if (ReadRaster(fd, LM_to_uint(buf[4], buf[5]), LM_to_uint(buf[6], buf[7]), image->bm, rowlen) == BAD) return BAD; else return OK; } } } ReadColorMap (fd, number, buffer) FILE *fd; int number; unsigned char *buffer; { int i; unsigned char rgb[3], *red, *grn, *blu; red = buffer; grn = buffer + number; blu = grn + number; for (i = 0; i < number; i++) { if (!ReadOK (fd, rgb, sizeof(rgb))) EasyFail("Bogus colormap\n", BAD); red[i] = rgb[0]; grn[i] = rgb[1]; blu[i] = rgb[2]; } return OK; } IgnoreExtention(fd) FILE *fd; { static char buf[256]; unsigned char c; while (1) { if (!ReadOK (fd, &c, 1)) EasyFail("EOF in extention\n", BAD); if (c == 0) return OK; if (read(fd, buf, (int) c) != (int) c) EasyFail("EOF in extention\n", BAD); } } GetCode(fd, code_size, flag) FILE *fd; int code_size; int flag; { static unsigned char buf[280]; static int curbit, lastbit, done, last_byte; int i, j, ret; unsigned char count; if (flag) { curbit = 0; lastbit = 0; done = FALSE; return 0; } if ((curbit + code_size) >= lastbit) { if (done) { if (curbit >= lastbit) EasyFail("Ran off the end of my bits\n", -1); } buf[0] = buf[last_byte - 2]; buf[1] = buf[last_byte - 1]; if (!ReadOK (fd, &count, 1)) { EasyFail("Error in getting buffer size\n", -1); } if (count == 0) { done = TRUE; } else if (!ReadOK (fd, &buf[2], count)) EasyFail("Error in getting buffer\n", -1); last_byte = 2 + count; curbit = (curbit - lastbit) + 16; lastbit = (2 + count) * 8; } ret = 0; for (i = curbit, j = 0; j < code_size; i++, j++) ret |= ((buf[i / 8] & (1 << (i % 8))) != 0) << j; curbit += code_size; return ret; } LWZReadByte(fd, flag, input_code_size) FILE *fd; int flag; int input_code_size; { static int fresh = FALSE; int code, incode; static int code_size, set_code_size; static int max_code, max_code_size; static int firstcode, oldcode; static int clear_code, end_code; static int table[2][(1 << MAX_LWZ_BITS)]; static int stack[(1 << (MAX_LWZ_BITS)) * 2], *sp; register int i; if (flag) { 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; GetCode(fd, 0, TRUE); fresh = TRUE; 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][0] = 0; sp = stack; return 0; } else if (fresh) { fresh = FALSE; do { firstcode = oldcode = GetCode(fd, code_size, FALSE); } while (firstcode == clear_code); return firstcode; } if (sp > stack) return *--sp; while ((code = GetCode(fd, code_size, FALSE)) >= 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; firstcode = oldcode = GetCode(fd, code_size, FALSE); return firstcode; } else if (code == end_code) { unsigned char count; unsigned char junk; while (ReadOK (fd, &count, 1) && (count != 0)) while (count-- != 0 && ReadOK (fd, &junk, 1)); if (count != 0) EasyFail("missing EOD in data stream (common occurance)\n", -3); 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]) EasyFail("Circular table entry BIG ERROR\n", -1); 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; } ReadInterlaced(fd, len, height, buffer, rowlen) FILE *fd; int len, height; unsigned char *buffer; int rowlen; { unsigned char c; register unsigned char *bmp; register int v; register int xpos = 0; register int ypos = 0, pass = 0; register int maxypos = 0; if (!ReadOK(fd, &c, 1)) EasyFail("Bogus image data -- EOF\n", BAD); if (LWZReadByte(fd, TRUE, c) < 0) return BAD; while ((v = LWZReadByte(fd, FALSE, c)) >= 0) { if (xpos == 0) { bmp = &(buffer[ypos * rowlen]); if (ypos > height) { fprintf (stderr, "Wanring Too much data, started to read line %d\n", ypos); return (OK); } } *bmp++ = v; if (++xpos == len) { xpos = 0; switch (pass) { case 0: case 1: ypos += 8; break; case 2: ypos += 4; break; case 3: ypos += 2; break; } if (ypos > maxypos) maxypos = ypos; if (ypos >= height) { switch (++pass) { case 1: ypos = 4; break; case 2: ypos = 2; break; case 3: ypos = 1; break; } } } } if (maxypos >= height) return OK; if (v == (-2)) return OK; return BAD; } ReadRaster (fd, len, height, buffer, rowlen) FILE *fd; int len, height; unsigned char *buffer; int rowlen; { unsigned char c; register unsigned char *bmp; register int v; register int xpos = 0; register int ypos = 0; if (!ReadOK (fd, &c, 1)) EasyFail("Bogus image data -- EOF\n", TRUE); if (LWZReadByte(fd, TRUE, c) < 0) return BAD; /* Read the raster data and dump it into the FBM bitmap */ while ((v = LWZReadByte(fd, FALSE, c)) >= 0) { if (xpos == 0) { bmp = &(buffer[ypos++ * rowlen]); if (ypos > height) { fprintf (stderr, "Warning: too much data, started to read line %d\n", ypos); return (OK); } } *bmp++ = v; if (++xpos == len) if (xpos == len) xpos = 0; } fprintf (stderr, "Done storing bitmap, xpos %d, ypos %d [%dx%d]\n", xpos, ypos, len, height); if (ypos >= height) return OK; if (v == (-2)) return OK; return BAD; }