www.pudn.com > speakfs72.zip > GIFTOBMP.C, change:2002-01-05,size:15415b


 
/* 
	 
		Convert in-memory face GIF file to BMP format. 
		 
		based on the NETPBM utility GIFTOPNM: 
 
*/ 
 
/* +-------------------------------------------------------------------+ */ 
/* | Copyright 1990, 1991, 1993, 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 "netfone.h" 
 
#define MAXCOLORMAPSIZE		256 
 
#define CM_RED				0 
#define CM_GREEN			1 
#define CM_BLUE				2 
 
#define MAX_LWZ_BITS		12 
 
#define INTERLACE			0x40 
#define LOCALCOLORMAP		0x80 
#define BitSet(byte, bit)	(((byte) & (bit)) == (bit)) 
 
#define PBM_TYPE			1 
#define PGM_TYPE			2 
#define PPM_TYPE			3 
 
static LPBYTE gifFile;				// In-memory GIF file pointer 
static long gifAddr;				// "Seek address" in GIF file 
static LPBYTE bmpFile = NULL;		// In-memory BMP file being constructed 
 
#define ReadOK(file, buffer, len) ((_fmemcpy(buffer, gifFile + gifAddr, len), gifAddr += len), TRUE) 
 
#define LM_to_uint(a, b)	(((b) << 8) | (a)) 
 
struct GifScreenStruct { 
	   unsigned int Width; 
	   unsigned int Height; 
	   unsigned char ColorMap[3][MAXCOLORMAPSIZE]; 
	   unsigned int BitPixel; 
	   unsigned int ColorResolution; 
	   unsigned int Background; 
	   unsigned int AspectRatio; 
	   int GrayScale; 
}; 
 
static struct { 
	   int	   transparent; 
	   int	   delayTime; 
	   int	   inputFlag; 
	   int	   disposal; 
} Gif89 = { -1, -1, -1, 0 }; 
 
/*	GIFtoBMP uses a lot of storage for LZW decoding, colour map 
	tables etc.  To avoid busting DGROUP in 16 bit medium memory 
	model or going to large model (which would block multiple 
	instances running at once), we define these buffers as members 
	of a "context" structure which is allocated from the global heap 
	for the duration of our processing.  */ 
 
static struct context { 
	struct GifScreenStruct c_GifScreen; 
	unsigned char c_GetCodebuf[280]; 
	int c_LZWtable[2][(1 << MAX_LWZ_BITS)]; 
	int c_LZWstack[(1 << (MAX_LWZ_BITS)) * 2]; 
	unsigned char c_localColorMap[3][MAXCOLORMAPSIZE]; 
} FAR *GIFcontext = NULL; 
 
//	Now define shortcuts to access items in the context 
 
#define	GifScreen		GIFcontext->c_GifScreen 
#define GetCodebuf		GIFcontext->c_GetCodebuf 
#define LZWtable		GIFcontext->c_LZWtable 
#define LZWstack		GIFcontext->c_LZWstack 
#define localColorMap	GIFcontext->c_localColorMap 
 
#define pm_error(x) { fatal = TRUE;		\ 
					  if (GIFcontext != NULL) { GlobalFreePtr(GIFcontext); GIFcontext = NULL; } \ 
					  if (bmpFile != NULL) { GlobalFreePtr(bmpFile); bmpFile = NULL; } \ 
					  return FALSE; } 
 
static int fatal; 
static int ZeroDataBlock = FALSE; 
 
//	READCOLORMAP  --  Read colour palette table 
 
static int ReadColorMap(int number, unsigned char FAR buffer[3][MAXCOLORMAPSIZE]) 
{ 
	   int i; 
	   unsigned char rgb[3]; 
	   int flag; 
 
	   flag = FALSE; 
 
	   for (i = 0; i < number; ++i) { 
			   ReadOK(fd, rgb, sizeof(rgb)); 
 
			   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]); 
	   } 
	   return TRUE; 
} 
 
//	GETDATABLOCK  --  Read a variable-sized data block 
 
static int GetDataBlock(LPBYTE buf) 
{ 
	   unsigned char count; 
 
	   ReadOK(fd, &count, 1); 
 
	   ZeroDataBlock = count == 0; 
 
	   if (count == 0) { 
			   return -1; 
	   } 
	   ReadOK(fd, buf, count); 
 
	   return count; 
} 
 
//	GETCODE  --  Read LZW code 
 
static int GetCode(int code_size, int flag) 
{ 
	   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) { 
					   return -1; 
			   } 
			   GetCodebuf[0] = GetCodebuf[last_byte - 2]; 
			   GetCodebuf[1] = GetCodebuf[last_byte - 1]; 
 
			   if ((count = GetDataBlock(&GetCodebuf[2])) == 0) 
					   done = TRUE; 
 
			   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 |= ((GetCodebuf[ i / 8 ] & (1 << (i % 8))) != 0) << j; 
 
	   curbit += code_size; 
 
	   return ret; 
} 
 
//	LWZREADBYTE  --  Read next uncompressed byte from the compressed stream 
 
static int LWZReadByte(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 FAR *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(0, TRUE); 
			    
			   fresh = TRUE; 
 
			   for (i = 0; i < clear_code; ++i) { 
					   LZWtable[0][i] = 0; 
					   LZWtable[1][i] = i; 
			   } 
			   for (; i < (1 << MAX_LWZ_BITS); ++i) 
					   LZWtable[0][i] = LZWtable[1][0] = 0; 
 
			   sp = LZWstack; 
 
			   return 0; 
	   } else if (fresh) { 
			   fresh = FALSE; 
			   do { 
					   firstcode = oldcode = 
							   GetCode(code_size, FALSE); 
			   } while (firstcode == clear_code); 
			   return firstcode; 
	   } 
 
	   if (sp > LZWstack) 
			   return *--sp; 
 
	   while ((code = GetCode(code_size, FALSE)) >= 0) { 
			   if (code == clear_code) { 
					   for (i = 0; i < clear_code; ++i) { 
							   LZWtable[0][i] = 0; 
							   LZWtable[1][i] = i; 
					   } 
					   for (; i < (1 << MAX_LWZ_BITS); ++i) 
							   LZWtable[0][i] = LZWtable[1][i] = 0; 
					   code_size = set_code_size + 1; 
					   max_code_size = 2 * clear_code; 
					   max_code = clear_code + 2; 
					   sp = LZWstack; 
					   firstcode = oldcode = 
									   GetCode(code_size, FALSE); 
					   return firstcode; 
			   } else if (code == end_code) { 
					   int count; 
					   unsigned char buf[260]; 
 
					   if (ZeroDataBlock) 
							   return -2; 
 
					   while ((count = GetDataBlock(buf)) > 0) ; 
					   return -2; 
			   } 
 
			   incode = code; 
 
			   if (code >= max_code) { 
					   *sp++ = firstcode; 
					   code = oldcode; 
			   } 
 
			   while (code >= clear_code) { 
					   *sp++ = LZWtable[1][code]; 
					   if (code == LZWtable[0][code]) { 
                       	   fatal = TRUE; 
                       	   return -1; 
                       } 
					   code = LZWtable[0][code]; 
			   } 
 
			   *sp++ = firstcode = LZWtable[1][code]; 
 
			   if ((code = max_code) <(1 << MAX_LWZ_BITS)) { 
					   LZWtable[0][code] = oldcode; 
					   LZWtable[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 > LZWstack) 
					   return *--sp; 
	   } 
	   return code; 
} 
 
//	DOEXTENSION  --  Process extension items 
 
static int DoExtension(int label) 
{ 
	   char buf[256]; 
#ifdef GIF_DEBUG	    
	   char *str; 
#endif	    
 
	   switch (label) { 
	   case 0x01:			   /* Plain Text Extension */ 
#ifdef GIF_DEBUG	    
               str = "Plain Text Extension"; 
#endif	    
			   break;  
			    
	   case 0xff:			   /* Application Extension */ 
#ifdef GIF_DEBUG	    
               str = "Application Extension"; 
#endif	    
			   break; 
			    
	   case 0xfe:			   /* Comment Extension */ 
#ifdef GIF_DEBUG	    
               str = "Comment Extension"; 
#endif 
         // This line should fix many crashes because John Walker was 
         // originally checking for a zero return, which would never 
         // occur because if the block is zero length, GetDataBlock() 
         // returns -1, never 0. 
			   while (GetDataBlock((unsigned char *) buf) != -1) { 
			   } 
			   return FALSE; 
			    
	   case 0xf9:			   /* Graphic Control Extension */ 
#ifdef GIF_DEBUG	    
               str = "Graphic Control Extension"; 
#endif	    
			   (void) GetDataBlock((unsigned char *) buf); 
			   Gif89.disposal = (buf[0] >> 2) & 0x7; 
			   Gif89.inputFlag = (buf[0] >> 1) & 0x1; 
			   Gif89.delayTime = LM_to_uint(buf[1],buf[2]); 
			   if ((buf[0] & 0x1) != 0) 
					   Gif89.transparent = buf[3]; 
 
         // This line should fix many crashes because John Walker was 
         // originally checking for a zero return, which would never 
         // occur because if the block is zero length, GetDataBlock() 
         // returns -1, never 0. 
			   while (GetDataBlock((unsigned char *) buf) != -1) ; 
			   return FALSE; 
			    
	   default: 
			   break; 
	   } 
 
     // This line should fix many crashes because John Walker was 
     // originally checking for a zero return, which would never 
     // occur because if the block is zero length, GetDataBlock() 
     // returns -1, never 0. 
	   while (GetDataBlock((unsigned char *) buf) != -1) ; 
 
	   return FALSE; 
} 
 
/*	READIMAGE  --  Read all components of image and, if successful, 
				   create the in-memory .BMP file.  */ 
 
static int ReadImage(int len, int height, 
					 int ncolours, unsigned char FAR cmap[3][MAXCOLORMAPSIZE], 
					 int interlace, int ignore) 
{ 
	   unsigned char c;	    
	   int v, linelen; 
	   int xpos = 0, ypos = 0, pass = 0; 
	   DWORD bfsize; 
	   BYTE _huge *pixels; 
	   LPBITMAPFILEHEADER bfh; 
	   LPBITMAPINFO bi; 
	   LPBITMAPINFOHEADER bh; 
 
	   //  Initialize the Compression routines 
	    
	   ReadOK(fd, &c, 1); 
 
	   if (LWZReadByte(TRUE, c) < 0) 
               return FALSE; 
 
       //  If this is an "uninteresting picture" ignore it. 
 
	   if (ignore) { 
			   while (LWZReadByte(FALSE, c) >= 0) ; 
			   return FALSE; 
	   } 
	    
	   //  Allocate the in-memory bitmap file. 
	    
	   linelen = (len + 3) & (~3); 
	   bmpFile = (LPBYTE) GlobalAllocPtr(GPTR, bfsize = 
	   				sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 
	   				256 * sizeof(RGBQUAD) + (linelen * ((DWORD) height))); 
	   bfh = (LPBITMAPFILEHEADER) bmpFile; 
	   bi = (LPBITMAPINFO) (bmpFile + sizeof(BITMAPFILEHEADER)); 
	   bh = &(bi->bmiHeader);  
	   pixels = bmpFile + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 
	   				256 * sizeof(RGBQUAD); 
	   				 
	   //	Build file header 
	    
	   _fmemcpy(&bfh->bfType, "BM", 2); 
	   bfh->bfSize = bfsize; 
	   bfh->bfOffBits = ((LPBYTE) pixels) - bmpFile; 
	    
	   //	Build BITMAPINFOHEADER 
	    
	   bh->biSize = sizeof(BITMAPINFOHEADER); 
	   bh->biWidth = len; 
	   bh->biHeight = height; 
	   bh->biPlanes = 1; 
	   bh->biBitCount = 8; 
	   bh->biCompression = BI_RGB; 
	   bh->biSizeImage = 0; 
	   bh->biClrUsed = bh->biClrImportant = ncolours; 
	    
	   //	Transcribe colour table to the bmiColors list 
	    
	   for (v = 0; v < ncolours; v++) { 
	       bi->bmiColors[v].rgbRed = cmap[CM_RED][v]; 
	       bi->bmiColors[v].rgbGreen = cmap[CM_GREEN][v]; 
	       bi->bmiColors[v].rgbBlue = cmap[CM_BLUE][v]; 
	   }   
 
	   while ((v = LWZReadByte(FALSE, c)) >= 0 ) { 
	   		   if (ypos > 0 && ypos < height) { 
	               pixels[(linelen * ((DWORD) ((height - 1) - ypos))) + xpos] = v; 
	           } 
 
			   ++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 fini; 
									   } 
							   } 
					   } else { 
							   ++ypos; 
					   } 
			   } 
			   if (ypos >= height) 
					   break; 
	   } 
 
fini: 
		return TRUE; 
} 
 
/*	GIFTOBMP  --  Convert an in-memory GIF file to an in-memory 
				  .BMP file.  Returns NULL if anything went wrong 
				  in the conversion process.  */ 
 
LPBYTE GIFtoBMP(LPBYTE gif, int imageNumber) 
{ 
	   unsigned char buf[16]; 
	   unsigned char c; 
	   int useGlobalColormap; 
	   int bitPixel; 
	   int imageCount = 0; 
	   char version[4]; 
        
       gifFile = gif; 
       gifAddr = 0; 
       fatal = FALSE; 
	   ReadOK(fd, buf, 6); 
 
       if (strncmp((char *) buf,"GIF",3) != 0) 
               pm_error("not a GIF file"); 
 
	   strncpy(version, (char *) buf + 3, 3); 
       version[3] = '\0'; 
 
       if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) 
               pm_error("bad version number, not '87a' or '89a'"); 
                
       GIFcontext = (struct context FAR *) GlobalAllocPtr(GPTR, sizeof(struct context)); 
       if (GIFcontext == NULL) { 
           return NULL; 
       } 
 
	   ReadOK(fd,buf,7); 
 
	   GifScreen.Width = LM_to_uint(buf[0], buf[1]); 
	   GifScreen.Height = LM_to_uint(buf[2], buf[3]); 
	   GifScreen.BitPixel = 2 << (buf[4] & 0x07); 
	   GifScreen.ColorResolution = (((buf[4] & 0x70) >> 3) + 1); 
	   GifScreen.Background = buf[5]; 
	   GifScreen.AspectRatio = buf[6]; 
 
	   if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */ 
			   if (!ReadColorMap(GifScreen.BitPixel, GifScreen.ColorMap)) 
                       pm_error("error reading global colormap"); 
	   } 
 
	   for (;;) { 
			   ReadOK(fd, &c, 1); 
 
               if (c == ';') {         /* GIF terminator */ 
					   if (imageCount < imageNumber) 
                               pm_error("Too few images found in file"); 
                       if (GIFcontext != NULL) { 
                       	   GlobalFreePtr(GIFcontext); 
                       	   GIFcontext = NULL; 
                       } 
					   return bmpFile; 
			   } 
 
               if (c == '!') {         /* Extension */ 
					   ReadOK(fd, &c, 1); 
					   DoExtension(c); 
					   continue; 
			   } 
 
               if (c != ',') {         /* Not a valid start character */ 
					   continue; 
			   } 
 
			   ++imageCount; 
 
			   ReadOK(fd, buf, 9); 
 
			   useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP); 
 
			   bitPixel = 1 << ((buf[8] & 0x07) + 1); 
 
			   if (!useGlobalColormap) { 
					   if (!ReadColorMap(bitPixel, localColorMap)) 
                               pm_error("error reading local colormap"); 
					   ReadImage(LM_to_uint(buf[4], buf[5]), 
								 LM_to_uint(buf[6], buf[7]),  
								 bitPixel, localColorMap, 
								 BitSet(buf[8], INTERLACE), imageCount != imageNumber); 
			   } else { 
					   ReadImage(LM_to_uint(buf[4], buf[5]), 
								 LM_to_uint(buf[6], buf[7]),  
								 GifScreen.BitPixel, GifScreen.ColorMap, 
								 BitSet(buf[8], INTERLACE), imageCount != imageNumber); 
			   } 
 
	   } 
}