/* gifread.c given a filename.gif, alpha, returns width, height, rgb pixels */ /* int width, height; int alpha=0 to 255, or -1 for just rgb */ /* unsigned char pixels[4*width*height]; or 3*width*height for alpha=-1 */ /* call: status = gifread("your-filename", alpha, &width, &height, pixels);*/ /* status==0 for OK */ #include "gif.h" #include #include static FILE *fpGif; /* Pointer to the input FILE stream, global for decoder */ static int bad_code_count; /* set by decoder */ static int gifReadHead(char gifFileName[], BYTE rgbpix[]); static short int gif_decode(short int linewidth, BYTE rgbpix[]); static int nrgbpix; static int debug = 0; /* set to 1 for full debug printout */ static int line_num; static int ipass; static int rgba=0; static int alph; static GIFHEAD gifHead; /* GIF Header structure */ static GIFIMAGEDESC gifImageDesc; /* Logical Image Descriptor struct */ #define OUT_OF_MEMORY -10 #define BAD_CODE_SIZE -20 #define READ_ERROR -1 #define WRITE_ERROR -2 #define OPEN_ERROR -3 #define CREATE_ERROR -4 int gifread(char filename[], int alpha, int *width, int *height, BYTE rgbpix[]) { int status; line_num = 0; /* needed for multiple calls in one program */ nrgbpix = 0; ipass = 1; /* pass number of interlace */ rgba = 0; if(alpha>=0 && alpha<=255) { rgba = 1; alph = alpha; } /* 4 bytes per pixel */ status = gifReadHead(filename, rgbpix); *width = gifImageDesc.ImageWidth; *height = gifImageDesc.ImageHeight; return status; } /* end gifread */ static int gifReadHead(char gifFileName[], BYTE rgbpix[]) { WORD i, j; /* Loop counter */ WORD tableSize; /* Number of entires in the global color table */ WORD lineCount; /* Count of the number of table lines displayed */ WORD imageCount; /* Count of the number of images in the file */ WORD blockCount; /* Running count of the number of data blocks */ BYTE Identifier; /* Extension block identifier holder */ BYTE Label; /* Extension block label holder */ BYTE dataSize; /* Size of data sub-block holder */ int blkSize; /* Data block byte count, (int) of above */ BYTE dataBlock[256]; /* Hold a data block */ BYTE *ptr; /* Scratch pointer variable */ BYTE code_size; short int err; GIFPLAINTEXT gifPlainText; /* Plain Text Extension structure */ GIFAPPLICATION gifApplication; /* Application Extension structure */ GIFCOMMENT gifComment; /* Comment Extension structure */ GIFGRAPHICCONTROL gifGraphicControl; /* Graphic Control Extension strct */ if(debug)printf("gifhead - Display the header info within a GIF image file \n"); /* Open the GIF image file */ if ((fpGif = fopen(gifFileName, "rb")) == (FILE *) NULL) { printf("gifhead: Cannot open file %s\n", gifFileName); return -1; } /* Read the GIF image file header information */ ReadGifHeader(&gifHead, fpGif); /* Check for FILE stream error */ if (ferror(fpGif)) { printf("gifhead: Error reading header information!\n"); return -1; } if(debug)printf(" Signature: %.*s\n", sizeof(gifHead.Signature), gifHead.Signature); if(debug)printf(" Version: %.*s\n", sizeof(gifHead.Version), gifHead.Version); if(debug)printf(" ScreenWidth: %u\n", gifHead.ScreenWidth); if(debug)printf(" ScreenHeight: %u\n", gifHead.ScreenHeight); if(debug)printf(" Global Color Table is: %s\n", gifHead.PackedField & 0x80 ? "Present" : "Not Present"); if(debug)printf(" Original Resolution: %u (%u bits per primary color)\n", (gifHead.PackedField & 0x70) >> 4, ((gifHead.PackedField & 0x70) >> 4) + 1); if(debug)printf(" Global Color Table is: %s\n", gifHead.PackedField & 0x08 ? "Sorted" : "Not Sorted"); if(debug)printf(" Size of Global Color Table: %lu entries (%lu bytes)\n", 1L << ((gifHead.PackedField & 0x07) + 1), 3L * (1L << ((gifHead.PackedField & 0x07) + 1))); if(debug)printf("Size of Global Color Table Entry: %u bits per pixel\n", (gifHead.PackedField & 0x07) + 1); if(debug)printf(" Background Color Index: %u\n", gifHead.ColorIndex); if(debug)printf(" Pixel Aspect Ratio: %u\n", gifHead.AspectRatio); /* ** Read and display the global color table if present. */ if (gifHead.PackedField & 0x80) { lineCount = 0; /* Count of the number of lines displayed */ tableSize = (WORD) (1L << ((gifHead.PackedField & 0x07) + 1)); if(debug)puts("\n\n\t\t\t\tGlobal Color Table\n"); if(debug)printf("Color Red Grn Blu Color Red Grn Blu Color"); if(debug)printf(" Red Grn Blu Color Red Grn Blu\n"); /* Display the palette values */ for (i = 0; i < tableSize; i++) { if(debug)printf(" %3d %03u %03u %03u", i, gifHead.GlobalCT[i].Red, gifHead.GlobalCT[i].Green, gifHead.GlobalCT[i].Blue); /* Four entries per row */ if (i && i % 4 == 3) { if(debug)putchar('\n'); lineCount++; } else if(debug)fputs(" ", stdout); if (lineCount == 22) { if(debug)printf("\n\nColor Red Grn Blu Color Red Grn Blu"); if(debug)printf(" Color Red Grn Blu Color Red Grn Blu\n"); lineCount = 0; } } } /* ** Identify, read, and display block information. */ imageCount = 0; /* Clear the image counter */ for (;;) { Identifier = GetByte(fpGif); switch (Identifier) { case 0x3B: /* Trailer */ if(debug)printf("\n\nGIF Trailer found (end of GIF image file).\n\n"); fclose(fpGif); return(0); case 0x2C: /* Image Descriptor */ gifImageDesc.ImageSeparator = Identifier; if (ReadGifImageDesc(&gifImageDesc, fpGif) == -1) fputs("Error reading Image Descriptor information\n", stderr); imageCount++; if(debug)printf("\n\nImage Descriptor for Image %d\n\n", imageCount); if(debug)printf(" Image Left Position: %u\n", gifImageDesc.ImageLeft); if(debug)printf(" Image Top Position: %u\n", gifImageDesc.ImageTop); if(debug)printf(" Image Width: %u\n", gifImageDesc.ImageWidth); if(debug)printf(" Image Height: %u\n", gifImageDesc.ImageHeight); if(debug)printf(" Local Color Table is: %s\n", gifImageDesc.PackedField & 0x80 ? "Present" : "Not Present"); if(debug)printf(" Local Color Table Entries are: %s\n", gifImageDesc.PackedField & 0x20 ? "Sorted" : "Not Sorted"); if(debug)printf(" Image is: %sInterlaced\n", gifImageDesc.PackedField & 0x40 ? "" : "Not "); if(debug)printf(" Reserved: %u\n", (gifImageDesc.PackedField & 0x18) >> 3); if(debug)printf(" Size of Local Color Table: %lu entries (%lu bytes)\n", 1L << ((gifImageDesc.PackedField & 0x07) + 1), 3L * (1L << ((gifImageDesc.PackedField & 0x07) + 1))); if(debug)printf("Size of Local Color Table Entry: %u bits per pixel\n", (gifImageDesc.PackedField & 0x07) + 1); /* ** Read and display local color table, if present. */ if (gifImageDesc.PackedField & 0x80) { lineCount = 0; /* Count of the number of lines displayed */ tableSize = (WORD) (1L << ((gifImageDesc.PackedField & 0x07) + 1)); if(debug)puts("\n\n\t\t\t\tLocal Color Table\n"); if(debug)printf("Color Red Grn Blu Color Red Grn Blu"); if(debug)printf(" Color Red Grn Blu Color Red Grn Blu\n"); /* Display the palette values */ for (i = 0; i < tableSize; i++) { if(debug)printf(" %3d %03u %03u %03u", i, gifImageDesc.LocalCT[i].Red, gifImageDesc.LocalCT[i].Green, gifImageDesc.LocalCT[i].Blue); /* Four entries per row */ if (i && i % 4 == 3) { if(debug)putchar('\n'); lineCount++; } else if(debug)fputs(" ", stdout); if (lineCount == 22) { if(debug)printf("\n\nColor Red Grn Blu Color Red Grn Blu"); if(debug)printf(" Color Red Grn Blu Color Red Grn Blu\n"); lineCount = 0; } } if(debug)puts("\n"); } /* ** Skip past the encoded image data. */ if(debug)printf(" Image data: doing via gif_decode.c \n"); err=gif_decode(gifImageDesc.ImageWidth, rgbpix); err=GetByte(fpGif); /* final zero block */ if(debug)printf("gif_decode returned err=%d, bad_code_count=%d\n", (int)err, (int)bad_code_count); break; case 0x21: /* Extension Block */ Label = GetByte(fpGif); switch (Label) { case 0x01: /* Plain Text Extension */ if(debug)puts("\n\nPlain Text Extension\n"); gifPlainText.Introducer = Identifier; gifPlainText.Label = Label; if (ReadGifPlainText(&gifPlainText, fpGif)) fprintf(stderr, "Error reading Plain Text Extension information.\n"); if(debug)printf(" Block Size: %u\n", gifPlainText.BlockSize); if(debug)printf(" Text Grid Left Position: %u\n", gifPlainText.TextGridLeft); if(debug)printf(" Text Grid Right Position: %u\n", gifPlainText.TextGridTop); if(debug)printf(" Text Grid Width: %u\n", gifPlainText.TextGridWidth); if(debug)printf(" Text Grid Height: %u\n", gifPlainText.TextGridHeight); if(debug)printf(" Character Cell Width: %u\n", gifPlainText.CellWidth); if(debug)printf(" Character Cell Height: %u\n", gifPlainText.CellHeight); if(debug)printf(" Text Foreground Color Index: %u\n", gifPlainText.TextFgColorIndex); if(debug)printf(" Text Background Color Index: %u\n", gifPlainText.TextBgColorIndex); /* Display Plain Text Data */ ptr = gifPlainText.PlainTextData; while ((dataSize = *ptr++) != 0) { if(debug)printf("\nSize of Plain Text sub-block: %u\n", dataSize); if(debug)puts("\nText:"); while (dataSize--) if(debug)fputc(*ptr++, stdout); if(debug)putchar('\n'); } break; case 0xFE: /* Comment Extension */ if(debug)puts("\n\nComment Extension"); gifComment.Introducer = Identifier; gifComment.Label = Label; if (ReadGifComment(&gifComment, fpGif)) fprintf(stderr, "Error reading Comment Extension information\n"); /* Display Comment Data */ ptr = gifComment.CommentData; while ((dataSize = *ptr++) != 0) { if(debug)printf("\nSize of Comment sub-block: %u\n", dataSize); if(debug)puts("\nComment:"); while (dataSize--) if(debug)fputc(*ptr++, stdout); if(debug)putchar('\n'); } break; case 0xF9: /* Graphic Control Extension */ if(debug)puts("\n\nGraphics Control Extension\n"); gifGraphicControl.Introducer = Identifier; gifGraphicControl.Label = Label; if (ReadGifGraphicControl(&gifGraphicControl, fpGif)) fprintf(stderr, "Error reading Graphic Control Extension information\n"); if(debug)printf(" Block Size: %u\n", gifGraphicControl.BlockSize); if(debug)printf(" Reserved: %u\n", (gifGraphicControl.PackedField & 0xE0) >> 5); if(debug)printf(" Disposal Method: %u ", (gifGraphicControl.PackedField & 0x1D) >> 2); switch((gifGraphicControl.PackedField & 0x1D) >> 2) { case 0x00: if(debug)puts("(No Disposal Method Defined)"); break; case 0x01: if(debug)puts("(Do Not Dispose)"); break; case 0x02: if(debug)puts("(Restore to Background Color)"); break; case 0x03: if(debug)puts("(Restore to Previous Graphic)"); break; default: if(debug)puts("(To Be Defined)"); } if(debug)printf(" User Input Flag: User Input is %sExpected\n", gifGraphicControl.PackedField & 0x02 ? "" : "Not "); if(debug)printf(" Transparent Color Flag: Color Index Is %sPresent\n", gifGraphicControl.PackedField & 0x01 ? "" : "Not "); if(debug)printf(" Delay Time: %u\n", gifGraphicControl.DelayTime); if(debug)printf("Transparent Color Index: %u\n", gifGraphicControl.ColorIndex); /* Display Graphic Control Information */ while ((dataSize = GetByte(fpGif)) != 0) { if(debug)printf("\nSize of Graphic Control sub-block: %u\n", dataSize); if(debug)puts("Graphic Control Information:"); for (i = 0; i < dataSize; i++) if(debug)fputc(GetByte(fpGif), stdout); if(debug)putchar('\n'); } break; case 0xFF: /* Application Extension */ if(debug)puts("\n\nApplication Extension\n"); gifApplication.Introducer = Identifier; gifApplication.Label = Label; if (ReadGifApplication(&gifApplication, fpGif)) fprintf(stderr, "Error reading Application Extension information\n"); if(debug)printf("Block Size: %u\n", gifApplication.BlockSize); if(debug)printf("Application Identifier: %*u\n", sizeof(gifApplication.Identifier), gifApplication.Identifier); if(debug)printf("Authentication Code: %*u\n", sizeof(gifApplication.AuthentCode), gifApplication.AuthentCode); /* Display Application Data */ ptr = gifApplication.ApplicationData; while ((dataSize = *ptr++) != 0) { if(debug)printf("\nSize of Application sub-block: %u\n", dataSize); if(debug)puts("\nApplication Data:"); while (dataSize--) if(debug)fputc(*ptr++, stdout); if(debug)putchar('\n'); } break; default: if(debug)printf("\n\nUnknown Extension Label: 0x%02x\n", Label); break; } break; default: fprintf(stderr, "\n\nUnknown Block Separator Character: 0x%02x\n\n", Identifier); fclose(fpGif); return(-1); } } } /* end gifHead */ /* gif_decode.c - An LZW decoder for GIF JSS mods */ /* Copyright (C) 1987, by Steven A. Bennett */ /* Permission is given by the author to freely redistribute and include */ /* this code in any program as long as this credit is given where due. */ /* In accordance with the above, I want to credit Steve Wilhite who wrote */ /* the code which this is heavily inspired by... */ /* */ /* GIF and 'Graphics Interchange Format' are trademarks (tm) of */ /* Compuserve, Incorporated, an H&R Block Company. */ /* */ /* Release Notes: This file contains a decoder routine for GIF images */ /* which is similar, structurally, to the original routine by Steve Wilhite*/ /* It is, however, somewhat noticably faster in most cases. */ /* Various error codes used by decode.c */ /* extern int get_byte(); replaced by getc(fpGif) */ /* This external (machine specific) function is expected to return */ /* either the next byte from the GIF file, or a negative number, as */ /* defined in above errors */ /* extern int out_line(BYTE pixels[], int linelen, BYTE rgbpix[]); Now here. */ /* This function takes a full line of pixels (one byte per pixel) and */ /* displays them (or does whatever your program wants with them...). It */ /* should return zero, or negative if an error or some other event occurs */ /* which would require aborting the decode process... Note that the length */ /* passed will almost always be equal to the line length passed to the */ /* decoder function, with the sole exception occurring when an ending code */ /* occurs in an odd place in the GIF file... In any case, linelen will be */ /* equal to the number of pixels passed... */ int out_line(BYTE pixels[], int linelen, BYTE rgbpix[]) /* JSS */ { int i, j; BYTE r, g, b; int enough=26; int w, h, hw, x, y; w = gifImageDesc.ImageWidth; h = gifImageDesc.ImageHeight; if(rgba) { hw = 4*h*w; x = 4*w; } else { hw = 3*h*w; x = 3*w; } line_num++; /* number, not subscript */ for(i=0; i=hw) { ipass = 4; nrgbpix = x; /* start row 1 */ } } if(ipass==2) { nrgbpix = nrgbpix + (8-1)*x; /* every eighth */ if(nrgbpix>=hw) { ipass = 3; nrgbpix = 2*x; /* start row 2 */ } } if(ipass==1) { nrgbpix = nrgbpix + (8-1)*x; /* every eighth */ if(nrgbpix>=hw) { ipass = 2; nrgbpix = 4*x; /* start row 4 */ } } } return 0; } /* end out_line */ /* extern int bad_code_count; */ /* This value is the only other global required by the using program, and */ /* is incremented each time an out of range code is read by the decoder. */ /* When this value is non-zero after a decode, your GIF file is probably */ /* corrupt in some way... */ #define MAX_CODES 4095 /* Static variables */ static WORD curr_size; /* The current code size */ static WORD clear; /* Value for a clear code */ static WORD ending; /* Value for a ending code */ static WORD newcodes; /* First available code */ static WORD top_slot; /* Highest code for current size */ static WORD slot; /* Last read code */ /* The following static variables are used */ /* for separating out codes */ static WORD navail_bytes = 0; /* # bytes left in block */ static WORD nbits_left = 0; /* # bits left in current byte */ static BYTE b1; /* Current byte */ static BYTE byte_buff[257]; /* Current block */ static BYTE *pbytes; /* Pointer to next byte in block */ static int code_mask[13] = { 0, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF }; /* This function initializes the decoder for reading a new image. */ static WORD init_exp(WORD size) { if(debug)printf("gif_decode.c init_exp size=%d\n", (int)size); curr_size = size + 1; top_slot = 1 << curr_size; clear = 1 << size; ending = clear + 1; slot = newcodes = ending + 1; navail_bytes = nbits_left = 0; return(0); } /* end init_exp */ /* get_next_code() */ /* - gets the next code from the GIF file. Returns the code, or else */ /* a negative number in case of file errors... */ static WORD get_next_code() { WORD i, x; int ret; if (nbits_left == 0) { if (navail_bytes <= 0) { /* Out of bytes in current block, so read next block */ pbytes = byte_buff; if ((navail_bytes = getc(fpGif)) < 0) { printf("gif_decode.c get_next_code bad block size=%d\n", (int)navail_bytes); return navail_bytes; } else if (navail_bytes) { if(debug)printf("gif_decode.c get_next_code block size=%d\n", (int)navail_bytes); for (i = 0; i < navail_bytes; ++i) { if ((x = getc(fpGif)) < 0) return x; byte_buff[i] = x; } } else { printf("gif_decode.c get_next_code zero block size=%d\n", (int)navail_bytes); } } b1 = *pbytes++; nbits_left = 8; --navail_bytes; } ret = b1 >> (8 - nbits_left); while (curr_size > nbits_left) { if (navail_bytes <= 0) { /* Out of bytes in current block, so read next block */ pbytes = byte_buff; if ((navail_bytes = getc(fpGif)) < 0) return(navail_bytes); else if (navail_bytes) { for (i = 0; i < navail_bytes; ++i) { if ((x = getc(fpGif)) < 0) return x; byte_buff[i] = x; } } } b1 = *pbytes++; ret |= b1 << nbits_left; nbits_left += 8; --navail_bytes; } nbits_left -= curr_size; ret &= code_mask[curr_size]; /* printf("gif_decode.c get_next_code code=%d\n", (int)ret); */ return (WORD)ret; } /* end get_next_code */ /* The reason we have these seperated like this instead of using */ /* a structure like the original Wilhite code did, is because this */ /* stuff generally produces significantly faster code when compiled... */ /* This code is full of similar speedups... (For a good book on writing */ /* C for speed or for space optomisation, see Efficient C by Tom Plum, */ /* published by Plum-Hall Associates...) */ static BYTE stack[MAX_CODES + 1]; /* Stack for storing pixels */ static BYTE suffix[MAX_CODES + 1]; /* Suffix table */ static unsigned int prefix[MAX_CODES + 1]; /* Prefix linked list */ /* - This function decodes an LZW image, according to the method used */ /* in the GIF spec. Every *linewidth* "characters" (ie. pixels) decoded */ /* will generate a call to out_line(), which is a user specific function */ /* to display a line of pixels. The function gets it's codes from */ /* get_next_code() which is responsible for reading blocks of data and */ /* seperating them into the proper size codes. Finally, getc(fpGif) is*/ /* the global routine to read the next byte from the GIF file. */ /* It is generally a good idea to have linewidth correspond to the actual */ /* width of a line (as specified in the Image header) to make your own */ /* code a bit simpler, but it isn't absolutely necessary. */ /* Returns: 0 if successful, else negative. (See ERRS.H) */ static short int gif_decode(short int linewidth, BYTE rgbpix[]) /* call with width, LZW initial code size, return is error code */ { register BYTE *sp, *bufptr; BYTE *buf; register WORD code, fc, oc, bufcnt; WORD c, size, ret; if(debug)printf("gif_decode.c linewidth=%d\n", (int)linewidth); /* Initialize for decoding a new image... */ if ((size = getc(fpGif)) < 0) return size; if (size < 2 || 9 < size) return BAD_CODE_SIZE; init_exp(size); /* Initialize in case they forgot to put in a clear code. */ /* (This shouldn't happen, but we'll try and decode it anyway...) */ oc = fc = 0; /* Allocate space for the decode buffer */ if ((buf = (BYTE *)malloc(linewidth + 1)) == NULL) return OUT_OF_MEMORY; /* Set up the stack pointer and decode buffer pointer */ sp = stack; bufptr = buf; bufcnt = linewidth; /* This is the main loop. For each code we get we pass through the */ /* linked list of prefix codes, pushing the corresponding "character" for */ /* each code onto the stack. When the list reaches a single "character" */ /* we push that on the stack too, and then start unstacking each */ /* character for output in the correct order. Special handling is */ /* included for the clear code, and the whole thing ends when we get */ /* an ending code. */ while ((c = get_next_code()) != ending) { /* If we had a file error, return without completing the decode */ if (c < 0) { free(buf); return 0; } /* If the code is a clear code, reinitialize all necessary items. */ if (c == clear) { curr_size = size + 1; slot = newcodes; top_slot = 1 << curr_size; /* Continue reading codes until we get a non-clear code */ /* (Another unlikely, but possible case...) */ while ((c = get_next_code()) == clear) ; /* If we get an ending code immediately after a clear code */ /* (Yet another unlikely case), then break out of the loop. */ if (c == ending) break; /* Finally, if the code is beyond the range of already set codes, */ /* (This one had better NOT happen... I have no idea what will */ /* result from this, but I doubt it will look good...) then set it */ /* to color zero. */ if (c >= slot) c = 0; oc = fc = c; /* And let us not forget to put the char into the buffer... And */ /* if, on the off chance, we were exactly one pixel from the end */ /* of the line, we have to send the buffer to the out_line() */ /* routine... */ *bufptr++ = c; if (--bufcnt == 0) { if ((ret = out_line(buf, linewidth, rgbpix)) < 0) { free(buf); return(ret); } bufptr = buf; bufcnt = linewidth; } } else { /* In this case, it's not a clear code or an ending code, so */ /* it must be a code code... So we can now decode the code into */ /* a stack of character codes. (Clear as mud, right?) */ code = c; /* Here we go again with one of those off chances... If, on the */ /* off chance, the code we got is beyond the range of those already */ /* set up (Another thing which had better NOT happen...) we trick */ /* the decoder into thinking it actually got the last code read. */ /* (Hmmn... I'm not sure why this works... But it does...) */ if (code >= slot) { if (code > slot) ++bad_code_count; code = oc; *sp++ = fc; } /* Here we scan back along the linked list of prefixes, pushing */ /* helpless characters (ie. suffixes) onto the stack as we do so. */ while (code >= newcodes) { *sp++ = suffix[code]; code = prefix[code]; } /* Push the last character on the stack, and set up the new */ /* prefix and suffix, and if the required slot number is greater */ /* than that allowed by the current bit size, increase the bit */ /* size. (NOTE - If we are all full, we *don't* save the new */ /* suffix and prefix... I'm not certain if this is correct... */ /* it might be more proper to overwrite the last code... */ *sp++ = code; if (slot < top_slot) { suffix[slot] = fc = code; prefix[slot++] = oc; oc = c; } if (slot >= top_slot) if (curr_size < 12) { top_slot <<= 1; ++curr_size; } /* Now that we've pushed the decoded string (in reverse order) */ /* onto the stack, lets pop it off and put it into our decode */ /* buffer... And when the decode buffer is full, write another*/ /* line... */ while (sp > stack) { *bufptr++ = *(--sp); if (--bufcnt == 0) { if ((ret = out_line(buf, linewidth, rgbpix)) < 0) { free(buf); return ret; } bufptr = buf; bufcnt = linewidth; } } } } ret = 0; if (bufcnt != linewidth) ret = out_line(buf, (linewidth - bufcnt), rgbpix); free(buf); return(ret); } /* end gif_decode */ /* gif_io.c implement low level I/O for Gif */ WORD GetWord(FILE *FpGif) /* little endian */ { int low, high; /* native machine */ WORD word; low = getc(FpGif); high = getc(FpGif); word = low; word = word+ (high<<8); return word; } /* end GetWord */ BYTE GetByte(FILE *FpGif) { return getc(FpGif); } /* end GetByte */ DWORD GetDword(FILE *FpGif) { int b1, b2, b3, b4; /* native machine */ WORD word; b1 = getc(FpGif); b2 = getc(FpGif); b3 = getc(FpGif); b4 = getc(FpGif); word = b1; word = word + (b2<<8) + (b3<<16) + (b4<24); return word; } /* end GetDword */ void GetString(char * str, int len, FILE *FpGif) { int i; for(i=0; i>8); putc(low, FpGif); putc(high, FpGif); } /* end PutWord */ void PutDword(DWORD x, FILE *FpGif) { BYTE b1, b2, b3, b4; b1 = (BYTE)(x & 0xFF); b2 = (BYTE)( (x>>8) & 0xFF); b3 = (BYTE)( (x>>16) * 0xFF); b4 = (BYTE)(x>>24); putc(b1, FpGif); putc(b2, FpGif); putc(b3, FpGif); putc(b4, FpGif); } /* end PutDword */ void PutString(char * str, int len, FILE *FpGif) { int i; for(i=0; iSignature, sizeof(GifHead->Signature), FpGif); GetString(GifHead->Version, sizeof(GifHead->Version), FpGif); GifHead->ScreenWidth = GetWord(FpGif); GifHead->ScreenHeight = GetWord(FpGif); GifHead->PackedField = GetByte(FpGif); GifHead->ColorIndex = GetByte(FpGif); GifHead->AspectRatio = GetByte(FpGif); /* Check if a Global Color Table is present */ if (GifHead->PackedField & 0x80) { /* Read number of color table entries */ tableSize = (WORD) (1L << ((GifHead->PackedField & 0x07) + 1)); /* Read the Global Color Table */ for (i = 0; i < tableSize; i++) { GifHead->GlobalCT[i].Red = GetByte(FpGif); GifHead->GlobalCT[i].Green = GetByte(FpGif); GifHead->GlobalCT[i].Blue = GetByte(FpGif); } } /* Check for a FILE stream error */ if (ferror(FpGif)) return -1; /* FILE stream error occured during read */ return 0; /* No FILE stream error occured */ } /* ** Read a GIF Local Image Descriptor. ** ** This function reads the Local Image Descriptor, and Local Color ** Table (if any) from a GIF image file. The information is stored ** in a GIFIMAGEDESC structure. ** ** Note that the ImageSeparator field value in the GIFIMAGEDESC ** structure is assigned by the function calling ReadGifImageDesc(). ** ** Returns: -1 if a FILE stream error occured during the read, ** otherwise 0 if no error occured. */ int ReadGifImageDesc( GIFIMAGEDESC *GifImageDesc, /* Pointer to GIF image descriptor structure */ FILE *FpGif) /* GIF image file input FILE stream */ { WORD i; /* Loop counter */ WORD tableSize; /* Number of entries in the Local Color Table */ /* GetWord = GetLittleWord; Read using little-endian byte order */ GifImageDesc->ImageLeft = GetWord(FpGif); GifImageDesc->ImageTop = GetWord(FpGif); GifImageDesc->ImageWidth = GetWord(FpGif); GifImageDesc->ImageHeight = GetWord(FpGif); GifImageDesc->PackedField = GetByte(FpGif); /* Check if a Local Color Table is present */ if (GifImageDesc->PackedField & 0x80) { /* Read number of color table entries */ tableSize = (WORD) (1L << ((GifImageDesc->PackedField & 0x07) + 1)); /* Read the Local Color Table */ for (i = 0; i < tableSize; i++) { GifImageDesc->LocalCT[i].Red = GetByte(FpGif); GifImageDesc->LocalCT[i].Green = GetByte(FpGif); GifImageDesc->LocalCT[i].Blue = GetByte(FpGif); } } /* Check for a FILE stream error */ if (ferror(FpGif)) return -1; /* FILE stream error occured during read */ return 0; /* No FILE stream error occured */ } /* ** Read a GIF Graphic Control Extension block. ** ** Note that the Introducer and Label field values in the GIFGRAPHICCONTROL ** structure are assigned by the function calling ReadGifGraphicControl(). ** ** Returns: -1 if a FILE stream error occured during the read, ** otherwise 0 if no error occured. */ int ReadGifGraphicControl( GIFGRAPHICCONTROL *GifGraphicControl, /* Pointer to GC Extension structure */ FILE *FpGif) /* GIF image file input FILE stream */ { /* GetWord = GetLittleWord; Read using little-endian byte order */ GifGraphicControl->BlockSize = GetByte(FpGif); GifGraphicControl->PackedField = GetByte(FpGif); GifGraphicControl->DelayTime = GetWord(FpGif); GifGraphicControl->ColorIndex = GetByte(FpGif); /* Check for a FILE stream error */ if (ferror(FpGif)) return -1; /* FILE stream error occured during read */ return 0; /* No FILE stream error occured */ } /* ** Read a GIF Plain Text Extension block. ** ** Note that the Introducer and Label field values in the GIFLPLAINTEXT ** structure are assigned by the function calling ReadGifPlainText(). ** ** Returns: -1 if a FILE stream error occured during the read, ** otherwise 0 if no error occured. */ int ReadGifPlainText( GIFPLAINTEXT *GifPlainText, /* Pointer to Plain Text Extension structure */ FILE *FpGif) /* GIF image file input FILE stream */ { /* GetWord = GetLittleWord; Read using little-endian byte order */ GifPlainText->BlockSize = GetByte(FpGif); GifPlainText->TextGridLeft = GetWord(FpGif); GifPlainText->TextGridTop = GetWord(FpGif); GifPlainText->TextGridWidth = GetWord(FpGif); GifPlainText->TextGridHeight = GetWord(FpGif); GifPlainText->CellWidth = GetByte(FpGif); GifPlainText->CellHeight = GetByte(FpGif); GifPlainText->TextFgColorIndex = GetByte(FpGif); GifPlainText->TextBgColorIndex = GetByte(FpGif); /* Read in the Plain Text data sub-blocks */ if (!(GifPlainText->PlainTextData = ReadDataSubBlocks(FpGif))) return 1; GifPlainText->Terminator = 0; /* Check for a FILE stream error */ if (ferror(FpGif)) return -1; /* FILE stream error occured during read */ return 0; /* No FILE stream error occured */ } /* ** Read a GIF Application Extension block. ** ** Note that the Introducer and Label field values in the GIFAPPLICATION ** structure are assigned by the function calling ReadGifApplication(). ** ** Returns: -1 if a FILE stream error occured during the read, ** otherwise 0 if no error occured. */ int ReadGifApplication( GIFAPPLICATION *GifApplication, /* Pointer to Application Extension struct */ FILE *FpGif) /* GIF image file input FILE stream */ { GifApplication->BlockSize = GetByte(FpGif); GifApplication->Identifier[0] = GetByte(FpGif); GifApplication->Identifier[1] = GetByte(FpGif); GifApplication->Identifier[2] = GetByte(FpGif); GifApplication->Identifier[3] = GetByte(FpGif); GifApplication->Identifier[4] = GetByte(FpGif); GifApplication->Identifier[5] = GetByte(FpGif); GifApplication->Identifier[6] = GetByte(FpGif); GifApplication->Identifier[7] = GetByte(FpGif); GifApplication->AuthentCode[0] = GetByte(FpGif); GifApplication->AuthentCode[1] = GetByte(FpGif); GifApplication->AuthentCode[2] = GetByte(FpGif); /* Read in the Plain Text data sub-blocks */ if (!(GifApplication->ApplicationData = ReadDataSubBlocks(FpGif))) return(1); GifApplication->Terminator = 0; /* Check for a FILE stream error */ if (ferror(FpGif)) return -1; /* FILE stream error occured during read */ return 0; /* No FILE stream error occured */ } /* ** Read a GIF Comment Extension block. ** ** Note that the Introducer and Label field values in the GIFCOMMENT ** structure are assigned by the function calling ReadGifComment(). ** ** Returns: -1 if a FILE stream error occured during the read, ** otherwise 0 if no error occured. */ int ReadGifComment( GIFCOMMENT *GifComment, /* Pointer to GIF Comment Extension structure */ FILE *FpGif) /* GIF image file input FILE stream */ { /* Read in the Plain Text data sub-blocks */ if (!(GifComment->CommentData = ReadDataSubBlocks(FpGif))) return(1); GifComment->Terminator = 0; /* Check for a FILE stream error */ if (ferror(FpGif)) return -1; /* FILE stream error occured during read */ return 0 ; /* No FILE stream error occured */ } /* ** Read one or more GIF data sub-blocks and write the information ** to a buffer. ** ** A GIF "sub-block" is a single count byte followed by 1 to 255 ** additional data bytes. ** ** Returns: A NULL pointer if a memory allocation error occured, ** otherwise a valid pointer if no error occured. */ BYTE * ReadDataSubBlocks(FILE *FpGif) /* GIF image file input FILE stream */ { BYTE *ptr1; /* Pointer used to "walk the heap" */ BYTE *ptr2; /* Pointer used to mark the top of the heap */ BYTE dataSize; /* Size of the current data sub-block being read */ WORD bufSize; /* Total size of the Plain Text data buffer */ bufSize = 0; /* The output buffer is empty */ dataSize = GetByte(FpGif); /* Get the size of the first sub-block */ /* Allocate initial data buffer */ if (!(ptr1 = ptr2 = (BYTE *) malloc(dataSize + 1))) return((BYTE *) NULL); for (;;) { bufSize += (dataSize + 1); /* Running total of the buffer size */ *ptr1++ = dataSize; /* Write the data count */ while (dataSize--) /* Read/write the Plain Text data */ *ptr1++ = GetByte(FpGif); /* Check if there is another data sub-block */ if ((dataSize = GetByte(FpGif)) == 0) break; /* Block Terminator encountered */ /* Increase the buffer size to accomodate the next sub-block */ if (!(ptr1 = ptr2 = (BYTE *) realloc(ptr2, dataSize + 1))) return((BYTE *) NULL); ptr1 += bufSize; /* Move pointer to the end of the data */ } *ptr1++ = (BYTE) NULL; /* Add NULL to simulate Terminator value */ return(ptr2); /* Return a pointer to the sub-block data */ } /* gifwrite.c */ /* These functions are the complement of the reader functions in GIFREAD.C. * They are used to write the header and data blocks found within the GIF *image file format. */ /****************************************************************************\ ** Title: gifwrite.c ** ** Purpose: Write GIF header information to a file. ** ** Version: 1.0 ** ** Date: May 1991 ** ** Author: James D. Murray, Anaheim, CA USA ** ** C Compilers: Borland C++ v2.0, Microsoft C v6.00a ** ** ** ** Write the information contained within a GIFHEADER structure ** ** to a file. Used to construct GIF-format files. ** ** ** ** This module contains the following functions: ** ** ** ** WriteGifHeader - Write a GIF header to a file stream ** ** ** ** Copyright (C) 1991 by Graphics Software Labs. All rights reserved. ** \****************************************************************************/ #include "gif.h" VOID WriteGifHeader(GIFHEAD *GifHead, /* Pointer to GIF header structure */ FILE *FpGif) /* GIF image file output FILE stream */ { /* PutWord = PutLittleWord; write using little-endian byte order */ PutString(GifHead->Signature, sizeof(GifHead->Signature), FpGif); PutString(GifHead->Version, sizeof(GifHead->Version), FpGif); PutWord(GifHead->ScreenWidth, FpGif); PutWord(GifHead->ScreenHeight, FpGif); PutByte(GifHead->PackedField, FpGif); PutByte(GifHead->ColorIndex, FpGif); PutByte(GifHead->AspectRatio, FpGif); } /* gifdecode.c GIF LZW Decoder */ /****************************************************************************\ ** Title: gifdecode.c ** ** Purpose: Decode a GIF image file scan line. ** ** Version: 1.0 ** ** Date: May 1991 ** ** Author: James D. Murray, Anaheim, CA USA ** ** C Compilers: Borland C++ v2.0, Microsoft C v6.00a ** ** ** ** Decompress an image scan line using the Lez-Zempel Welch (LZW) encoding ** ** algorithm. Decoded data is returned in a buffer. Useful for ** ** algorithms that need to work on images one scan line at a time. ** ** ** ** This module contains the following functions: ** ** ** ** GifDecodeScanLine - Decode an LZW-encoded scan line ** ** ** ** Copyright (C) 1991 by Graphics Software Labs. All rights reserved. ** \****************************************************************************/ #include "gif.h" /* ** Decode (uncompress) a GIF image file scan line. ** ** The LZW-encoded data stored in a GIF file is arranged as a series ** of sub-blocks. Each sub-lock consists of a single count byte followed ** by 1 to 255 data bytes. This function reads the sub-blocks, sends ** the LZW data to the LZWDecode() function, and then returns a parameter ** pointer to a buffer filled with the decoded image data. */ SHORT GIFDecodeScanLine( BYTE *DecodedBuffer, /* Pointer to buffer to hold decoded data */ WORD BufferSize, /* Size of buffer to hold decoded data */ BYTE MinCodeSize, /* */ FILE *FpGif) /* FILE pointer to the open input GIF image file*/ { #if 0 if (!(DecodedBuffer = LZWDecoder(buffer, bufferSize, MinCodeSize))) return -1; #endif return 0; } /* gifencode.c GIF LZW Encoder */ /****************************************************************************\ ** Title: GIFENCOD.C ** ** Purpose: Encode a GIF image file scan line. ** ** Version: 1.0 ** ** Date: May 1991 ** ** Author: James D. Murray, Anaheim, CA USA ** ** C Compilers: Borland C++ v2.0, Microsoft C v6.00a ** ** ** ** Compress an image scan line using the Lev-Zempel Welch (LZW) encoding ** ** algorithm. Useful for algorithms that need to work on images ** ** one scan line at a time. ** ** ** ** This module contains the following functions: ** ** ** ** GifEncodeScanLine - Encode a raw scan line using LZW. ** ** ** ** Copyright (C) 1991 by Graphics Software Labs. All rights reserved. ** \****************************************************************************/ #include "gif.h" WORD GifEncodeScanLine( BYTE *DecodedBuffer, /* Pointer to buffer holding unencoded data */ WORD BufferSize, /* Size of buffer holding unencoded data */ BYTE *EncodedBuffer) /* Pointer to buffer to hold encodeded scan line */ { return 0; }