www.pudn.com > viewImage.rar > GIFAPI.CPP


// ************************************************************************ 
//  文件名:GIFAPI.cpp 
// 
//  GIF(Graphics Interchange Format) API函数库: 
// 
//  DIBToGIF()          - 将指定的DIB对象(< 256色)保存为GIF文件 
//  EncodeGIF()		- 对指定图像进行GIF_LZW编码 
//  WriteCodeGIF() - 输出一个编码 
//  ReadGIF()           - 读取GIF文件 
//  DecodeGIF()     - 对GIF_LZW编码结果进行解码 
//  ReadSrcDataGIF()       - 读取GIF_LZW编码 
// 
// ************************************************************************ 
 
#include "stdafx.h" 
#include "DIBAPI.h" 
#include "GIFAPI.h" 
 
#include  
#include  
 
#include  
#include  
 
/************************************************************************* 
 * 
 * 函数名称: 
 *   DIBToGIF() 
 * 
 * 参数: 
 *   LPSTR lpDIB        - 指向DIB对象的指针 
 *   CFile& file        - 要保存的文件 
 *   BOOL	bInterlace	- 是否按照交错方式保存 
 * 
 * 返回值: 
 *   BOOL               - 成功返回True,否则返回False。 
 * 
 * 说明: 
 *   该函数将指定的DIB对象(< 256色)保存为GIF文件。 
 * 
 *************************************************************************/ 
BOOL SaveGIF(LPCSTR lpszFileName, LPSTR lpDIB, BOOL bInterlace) 
{ 
	// 循环变量 
	WORD	i; 
	WORD	j; 
	 
	// DIB高度 
	WORD	wHeight; 
	 
	// DIB宽度 
	WORD	wWidth; 
	 
	// 指向DIB象素指针 
	LPSTR   lpDIBBits; 
	 
	// GIF文件头 
	GIFHEADER          GIFH; 
	 
	// GIF逻辑屏幕描述块 
	GIFSCRDESC         GIFS; 
	 
	// GIF图像描述块 
	GIFIMAGE           GIFI; 
	 
	// GIF编码参数 
	GIFCONTROLPARAM    GIFControlParam; 
	 
	// 颜色数目 
	WORD               wColors; 
	 
	// 每行字节数 
	WORD               wWidthBytes; 
	 
	// 调色板 
	BYTE               byGIF_Pal[768]; 
	 
	// 字节变量 
	BYTE               byChar; 
	 
	// 指向BITMAPINFO结构的指针(Win3.0) 
	LPBITMAPINFO	   lpbmi; 
	 
	// 指向BITMAPCOREINFO结构的指针 
	LPBITMAPCOREINFO   lpbmc; 
	 
	// 表明是否是Win3.0 DIB的标记 
	BOOL			   bWinStyleDIB; 
 
	// open file 
	CFile file; 
	if (! file.Open(lpszFileName, CFile::modeCreate | CFile::modeWrite)) 
		return FALSE; 
	 
	// 获取DIB高度 
	wHeight = (WORD) DIBHeight(lpDIB); 
	 
	// 获取DIB宽度 
	wWidth  = (WORD) DIBWidth(lpDIB); 
	 
	// 找到DIB图像象素起始位置 
	lpDIBBits = (LPSTR)FindDIBBits((LPBYTE)lpDIB); 
	 
	// 给GIFControlParam结构赋值 
	GIFControlParam.wWidth     = wWidth; 
	GIFControlParam.wDepth     = wHeight; 
	GIFControlParam.wBits      = DIBBitCount(lpDIB); 
	GIFControlParam.wLineBytes = (WORD)BYTE_WBYTES((DWORD)GIFControlParam.wWidth * 
										   (DWORD)GIFControlParam.wBits); 
	 
	// 计算每行字节数 
	wWidthBytes = (WORD)DWORD_WBYTES(wWidth * (DWORD)GIFControlParam.wBits); 
	 
	// 计算颜色数目 
	wColors     = 1 << GIFControlParam.wBits; 
	 
	// 获取指向BITMAPINFO结构的指针(Win3.0) 
	lpbmi = (LPBITMAPINFO)lpDIB; 
	 
	// 获取指向BITMAPCOREINFO结构的指针 
	lpbmc = (LPBITMAPCOREINFO)lpDIB; 
	 
	// 判断是否是WIN3.0的DIB 
	bWinStyleDIB = IS_WIN30_DIB(lpDIB); 
	 
	// 给调色板赋值 
	if (bWinStyleDIB) 
	{ 
		j = 0; 
		for (i = 0; i < wColors; i++) 
		{ 
			// 读取红色分量 
			byGIF_Pal[j++] = lpbmi->bmiColors[i].rgbRed; 
			 
			// 读取绿色分量 
			byGIF_Pal[j++] = lpbmi->bmiColors[i].rgbGreen; 
			 
			// 读取蓝色分量 
			byGIF_Pal[j++] = lpbmi->bmiColors[i].rgbBlue; 
		} 
	} 
	else 
	{ 
		j = 0; 
		for (i = 0; i < wColors; i++) 
		{ 
			// 读取红色分量 
			byGIF_Pal[j++] = lpbmc->bmciColors[i].rgbtRed; 
			 
			// 读取绿色分量 
			byGIF_Pal[j++] = lpbmc->bmciColors[i].rgbtGreen; 
			 
			// 读取红色分量 
			byGIF_Pal[j++] = lpbmc->bmciColors[i].rgbtBlue; 
		} 
	} 
	 
	//////////////////////////////////////////////////////////////////////////////////////// 
	// 开始写GIF文件 
	 
	// 写GIF文件头 
	GIFH.bySignature[0] = 'G'; 
	GIFH.bySignature[1] = 'I'; 
	GIFH.bySignature[2] = 'F'; 
	GIFH.byVersion[0]='8'; 
	GIFH.byVersion[1]='9'; 
	GIFH.byVersion[2]='a'; 
	file.Write((LPSTR)&GIFH, 6); 
	 
	// 写GIF逻辑屏幕描述块 
	GIFS.wWidth               = GIFControlParam.wWidth; 
	GIFS.wDepth               = GIFControlParam.wDepth; 
	GIFS.GlobalFlag.PalBits   = (BYTE)(GIFControlParam.wBits - 1); 
	GIFS.GlobalFlag.SortFlag  = 0x00; 
	GIFS.GlobalFlag.ColorRes  = (BYTE)(GIFControlParam.wBits - 1); 
	GIFS.GlobalFlag.GlobalPal = 0x01; 
	GIFS.byBackground         = 0x00; 
	GIFS.byAspect             = 0x00; 
	file.Write((LPSTR)&GIFS, 7); 
	 
	// 写GIF全局调色板 
	file.Write((LPSTR)byGIF_Pal,(wColors*3)); 
	 
	// 写GIF图像描述间隔符 
	byChar      = 0x2C; 
	file.Write((LPSTR)&byChar,1); 
	 
	// 写GIF图像描述块 
	GIFI.wLeft                = 0; 
	GIFI.wTop                 = 0; 
	GIFI.wWidth               = GIFControlParam.wWidth; 
	GIFI.wDepth               = GIFControlParam.wDepth; 
	GIFI.LocalFlag.PalBits    = 0x00; 
	GIFI.LocalFlag.Reserved   = 0x00; 
	GIFI.LocalFlag.SortFlag   = 0x00; 
	GIFI.LocalFlag.Interlace  = (BYTE)(bInterlace ? 0x01 : 0x00); 
	GIFI.LocalFlag.LocalPal   = 0x00; 
	file.Write((LPSTR)&GIFI, 9); 
	 
	// 写GIF图像压缩数据 
	HANDLE hSrcBuff = GlobalAlloc(GHND,(DWORD)MAX_BUFF_SIZE); 
	GIFControlParam.lpDataBuff = (LPSTR)GlobalLock(hSrcBuff); 
	GIFControlParam.lpEndBuff  = GIFControlParam.lpDataBuff; 
	GIFControlParam.dwTempCode = 0UL; 
	GIFControlParam.wByteCnt   = 0; 
	GIFControlParam.wBlockNdx  = 1; 
	GIFControlParam.byLeftBits = 0x00; 
	 
	// 进行GIF_LZW编码 
	EncodeGIF(file, lpDIBBits, &GIFControlParam,wWidthBytes, bInterlace); 
	 
	// 判断是否编码成功 
	if (GIFControlParam.wByteCnt) 
	{ 
		// 写入文件 
		file.Write(GIFControlParam.lpDataBuff, GIFControlParam.wByteCnt); 
	} 
	 
	// 释放内存 
	GlobalUnlock(hSrcBuff); 
	GlobalFree(hSrcBuff); 
	 
	// 写GIF Block Terminator 
	byChar   = 0x00; 
	file.Write((LPSTR)&byChar,1); 
	 
	// 写GIF文件结尾块 
	byChar   = 0x3B; 
	file.Write((LPSTR)&byChar,1); 
	 
	// 返回 
	return TRUE; 
} 
 
/************************************************************************* 
 * 
 * 函数名称: 
 *   EncodeGIF() 
 * 
 * 参数: 
 *   LPSTR lpDIBBits		- 指向源DIB图像指针 
 *   CFile& file			- 要保存的文件 
 *   LPGIFCONTROLPARAM lpGIFControlParam	- 指向GIFCONTROLPARAM结构的指针 
 *	 WORD wWidthBytes		- 每行图像字节数 
 *	 BOOL bInterlace		- 是否按照交错方式保存 
 * 
 * 返回值: 
 *   无 
 * 
 * 说明: 
 *   该函数对指定图像进行GIF_LZW编码。 
 * 
 *************************************************************************/ 
void EncodeGIF(CFile& file, LPSTR lpDIBBits,  
						  LPGIFCONTROLPARAM lpGIFControlParam,WORD wWidthBytes, BOOL bInterlace) 
{ 
	// 内存分配句柄 
	HANDLE hTableNdx; 
	HANDLE hPrefix; 
	HANDLE hSuffix; 
	 
	// 指向字串表指针 
	LPWORD lpwTableNdx; 
	 
	// 用于字串表搜索的索引 
	LPWORD lpwPrefix; 
	LPBYTE lpbySuffix; 
	 
	// 指向当前编码像素的指针 
	LPSTR  lpImage; 
	 
	// 计算当前数据图像的偏移量 
	DWORD  dwDataNdx; 
	 
	// LZW_CLEAR 
	WORD   wLZW_CLEAR; 
	 
	// LZW_EOI 
	WORD   wLZW_EOI; 
	 
	// LZW_MinCodeLen 
	BYTE   byLZW_MinCodeLen; 
	 
	// 字串表索引 
	WORD   wPreTableNdx; 
	WORD   wNowTableNdx; 
	WORD   wTopTableNdx; 
	 
	// 哈希表索引 
	WORD   wHashNdx; 
	WORD   wHashGap; 
	WORD   wPrefix; 
	WORD   wShiftBits; 
	 
	// 当前图像的行数 
	WORD   wRowNum; 
	 
	WORD   wWidthCnt; 
	 
	// 循环变量 
	WORD   wi; 
	WORD   wj; 
	 
	// 交错方式存储时每次增加的行数 
	WORD   wIncTable[5]  = { 8,8,4,2,0 };  
	 
	// 交错方式存储时起始行数 
	WORD   wBgnTable[5]  = { 0,4,2,1,0 };  
	 
	BOOL   bStart; 
	BYTE   bySuffix; 
	BYTE   bySubBlock[256]; 
	BYTE   byCurrentBits; 
	BYTE   byMask; 
	BYTE   byChar; 
	BYTE   byPass; 
	 
	// 临时字节变量 
	BYTE   byTemp; 
	 
	// 给字串表分配内存 
	hTableNdx        = GlobalAlloc(GHND,(DWORD)(MAX_HASH_SIZE<<1)); 
	hPrefix          = GlobalAlloc(GHND,(DWORD)(MAX_HASH_SIZE<<1)); 
	hSuffix          = GlobalAlloc(GHND,(DWORD)MAX_HASH_SIZE); 
	 
	// 锁定内存 
	lpwTableNdx      = (LPWORD)GlobalLock(hTableNdx); 
	lpwPrefix        = (LPWORD)GlobalLock(hPrefix); 
	lpbySuffix       = (LPBYTE)GlobalLock(hSuffix); 
	 
	// 计算LZW_MinCodeLen 
	byLZW_MinCodeLen = (BYTE)((lpGIFControlParam->wBits>1) ? lpGIFControlParam->wBits : 0x02); 
	 
	// 写GIF LZW最小代码大小 
	file.Write((LPSTR)&byLZW_MinCodeLen,1); 
	 
	wRowNum          = 0; 
	bStart           = TRUE; 
	byPass           = 0x00; 
	 
	// 计算LZW_CLEAR 
	wLZW_CLEAR       = 1 << byLZW_MinCodeLen; 
	 
	// 计算LZW_EOI 
	wLZW_EOI         = wLZW_CLEAR + 1; 
	 
	// 初始化字串表 
	byCurrentBits    = byLZW_MinCodeLen + (BYTE)0x01; 
	wNowTableNdx     = wLZW_CLEAR + 2; 
	wTopTableNdx     = 1 << byCurrentBits; 
	for(wi=0; wiwDepth; wi++) 
	{ 
		// 计算当前偏移量 
		dwDataNdx  = (DWORD)(lpGIFControlParam->wDepth - 1 - wRowNum) * (DWORD)wWidthBytes; 
		 
		// 指向当前行图像的指针 
		lpImage    = (LPSTR) (((BYTE*)lpDIBBits) + dwDataNdx); 
		 
		wWidthCnt  = 0; 
		wShiftBits = 8 - lpGIFControlParam->wBits; 
		byMask     = (BYTE)((lpGIFControlParam->wBits==1) ? 0x80 : 0xF0); 
		 
		if (bStart) 
		{ 
			// 判断是否是256色位图(一个像素一字节) 
			if (lpGIFControlParam->wBits==8) 
			{ 
				// 256色,直接赋值即可 
				byTemp      = *lpImage++; 
			} 
			else 
			{ 
				// 非256色,需要移位获取像素值 
				wShiftBits  = 8 - lpGIFControlParam->wBits; 
				byMask      = (BYTE)((lpGIFControlParam->wBits==1) ? 0x80 : 0xF0); 
				byTemp      = (BYTE)((*lpImage & byMask) >> wShiftBits); 
				byMask    >>= lpGIFControlParam->wBits; 
				wShiftBits -= lpGIFControlParam->wBits; 
			} 
			wPrefix    = (WORD)byTemp; 
			bStart     = FALSE; 
			wWidthCnt ++; 
		} 
		 
		// 每行编码 
		while(wWidthCnt < lpGIFControlParam->wWidth) 
		{ 
			// 判断是否是256色位图(一个像素一字节) 
			if (lpGIFControlParam->wBits==8) 
			{ 
				// 256色,直接赋值即可 
				byTemp = *lpImage++; 
			} 
			else 
			{ 
				// 非256色,需要移位获取像素值 
				byChar = *lpImage; 
				byTemp = (BYTE)((byChar & byMask) >> wShiftBits); 
				if (wShiftBits) 
				{ 
					byMask    >>= lpGIFControlParam->wBits; 
					wShiftBits -= lpGIFControlParam->wBits; 
				} 
				else 
				{ 
					wShiftBits  = 8 - lpGIFControlParam->wBits; 
					byMask      = (BYTE)((lpGIFControlParam->wBits==1) ? 0x80 : 0xF0); 
					lpImage    ++; 
				} 
			} 
			bySuffix   = byTemp; 
			wWidthCnt ++; 
			 
			// 查找当前字符串是否存在于字串表中 
			wHashNdx = wPrefix ^ ((WORD)bySuffix << 4); 
			wHashGap = (wHashNdx ? (MAX_HASH_SIZE - wHashNdx) : 1); 
			 
			// 判断当前字符串是否在字串表中 
			while(TRUE) 
			{ 
				// 当前字符串不在字串表中 
				if (*(lpwTableNdx + wHashNdx) == 0xFFFF) 
				{ 
				   // 新字符串,退出循环 
				   break; 
				} 
				 
				// 判断是否找到该字符串 
				if ((*(lpwPrefix+wHashNdx)  == wPrefix) && 
					(*(lpbySuffix+wHashNdx) == bySuffix)) 
				{ 
					// 找到,退出循环 
					break; 
				} 
				 
				// 第二哈希表 
				if (wHashNdx < wHashGap) 
				{ 
					wHashNdx += MAX_HASH_SIZE; 
				} 
				wHashNdx -= wHashGap; 
			} 
			 
			// 判断是否是新字符串 
			if (*(lpwTableNdx+wHashNdx) != 0xFFFF) 
			{ 
				// 不是新字符串 
				wPrefix = *(lpwTableNdx + wHashNdx); 
			 } 
			 else 
			 { 
				// 新字符串 
				 
				// 输出该编码 
				WriteCodeGIF(file,wPrefix,(LPSTR)bySubBlock, 
								   &byCurrentBits,lpGIFControlParam); 
				 
				// 将该新字符串添加到字串表中 
				wPreTableNdx = wNowTableNdx; 
				 
				// 判断是否达到最大字串表大小 
				if (wNowTableNdx < MAX_TABLE_SIZE) 
				{ 
					*(lpwTableNdx+wHashNdx) = wNowTableNdx++; 
					*(lpwPrefix+wHashNdx)   = wPrefix; 
					*(lpbySuffix+wHashNdx)  = bySuffix; 
				} 
				 
				if (wPreTableNdx == wTopTableNdx) 
				{ 
					if (byCurrentBits<12) 
					{ 
						byCurrentBits ++; 
						wTopTableNdx <<= 1; 
					} 
					else 
					{ 
						// 字串表到达最大长度 
						 
						// 输出LZW_CLEAR 
						WriteCodeGIF(file, wLZW_CLEAR, (LPSTR)bySubBlock, 
										 &byCurrentBits,lpGIFControlParam); 
						 
						// 重新初始化字串表 
						byCurrentBits    = byLZW_MinCodeLen + (BYTE)0x01; 
						wLZW_CLEAR       = 1 << byLZW_MinCodeLen; 
						wLZW_EOI         = wLZW_CLEAR + 1; 
						wNowTableNdx     = wLZW_CLEAR + 2; 
						wTopTableNdx     = 1 << byCurrentBits; 
						for(wj=0;wj=lpGIFControlParam->wDepth) 
			{ 
				byPass ++; 
				wRowNum = wBgnTable[byPass]; 
			} 
		} 
		else 
		{ 
			// 非交错方式,直接将行数加一即可 
			wRowNum ++; 
		} 
	} 
	 
	// 输出当前编码 
	WriteCodeGIF(file, wPrefix, (LPSTR)bySubBlock, 
					  &byCurrentBits,lpGIFControlParam); 
	 
	// 输出LZW_EOI 
	WriteCodeGIF(file,wLZW_EOI,(LPSTR)bySubBlock, 
					  &byCurrentBits,lpGIFControlParam); 
	 
	if (lpGIFControlParam->byLeftBits) 
	{ 
		// 加入该字符 
		bySubBlock[lpGIFControlParam->wBlockNdx++] = (BYTE)lpGIFControlParam->dwTempCode; 
		 
		// 判断是否超出MAX_SUBBLOCK_SIZE 
		if (lpGIFControlParam->wBlockNdx > MAX_SUBBLOCK_SIZE) 
		{ 
			// 判断wByteCnt + 256是否超过MAX_BUFF_SIZE 
			if ((lpGIFControlParam->wByteCnt + 256) >= MAX_BUFF_SIZE) 
			{ 
				// 输出 
				file.Write(lpGIFControlParam->lpDataBuff, 
							  lpGIFControlParam->wByteCnt); 
				lpGIFControlParam->lpEndBuff = lpGIFControlParam->lpDataBuff; 
				lpGIFControlParam->wByteCnt  = 0; 
			} 
			bySubBlock[0]           = (BYTE)(lpGIFControlParam->wBlockNdx - 1); 
			memcpy(lpGIFControlParam->lpEndBuff,(LPSTR)bySubBlock,lpGIFControlParam->wBlockNdx); 
			lpGIFControlParam->lpEndBuff   += lpGIFControlParam->wBlockNdx; 
			lpGIFControlParam->wByteCnt    += lpGIFControlParam->wBlockNdx; 
			lpGIFControlParam->wBlockNdx    = 1; 
		} 
		lpGIFControlParam->dwTempCode = 0UL; 
		lpGIFControlParam->byLeftBits = 0x00; 
	} 
	 
	if (lpGIFControlParam->wBlockNdx > 1) 
	{ 
		// 判断wByteCnt + 256是否超过MAX_BUFF_SIZE 
		if ((lpGIFControlParam->wByteCnt + 256) >= MAX_BUFF_SIZE) 
		{ 
			// 输出 
			file.Write(lpGIFControlParam->lpDataBuff, 
						   lpGIFControlParam->wByteCnt); 
			lpGIFControlParam->lpEndBuff = lpGIFControlParam->lpDataBuff; 
			lpGIFControlParam->wByteCnt  = 0; 
		} 
		bySubBlock[0]           = (BYTE)(lpGIFControlParam->wBlockNdx - 1); 
		memcpy(lpGIFControlParam->lpEndBuff,(LPSTR)bySubBlock,lpGIFControlParam->wBlockNdx); 
		lpGIFControlParam->lpEndBuff   += lpGIFControlParam->wBlockNdx; 
		lpGIFControlParam->wByteCnt    += lpGIFControlParam->wBlockNdx; 
		lpGIFControlParam->wBlockNdx    = 1; 
	} 
	 
	// 解除锁定 
	GlobalUnlock(hTableNdx); 
	GlobalUnlock(hPrefix); 
	GlobalUnlock(hSuffix); 
	 
	// 释放内存 
	GlobalFree(hTableNdx); 
	GlobalFree(hPrefix); 
	GlobalFree(hSuffix); 
	 
	// 退出 
	return; 
} 
 
 
/************************************************************************* 
 * 
 * 函数名称: 
 *   WriteCodeGIF() 
 * 
 * 参数: 
 *   CFile& file			- 要保存的文件 
 *	 WORD wCode				- 要添加的编码 
 *   LPSTR lpSubBlock		- 子块 
 *	 LPBYTE lpbyCurrentBits	- 当前位数 
 *	 LPGIFCONTROLPARAM lpGIFControlParam	- 指向GIFCONTROLPARAM结构的指针 
 * 
 * 返回值: 
 *   无 
 * 
 * 说明: 
 *   该函数用来输出一个编码。 
 * 
 *************************************************************************/ 
void WriteCodeGIF(CFile& file, WORD wCode, LPSTR lpSubBlock, 
                              LPBYTE lpbyCurrentBits,LPGIFCONTROLPARAM lpGIFControlParam) 
{ 
	// 输出该编码 
	lpGIFControlParam->dwTempCode |= ((DWORD)wCode << lpGIFControlParam->byLeftBits); 
	lpGIFControlParam->byLeftBits += (*lpbyCurrentBits); 
	 
	while(lpGIFControlParam->byLeftBits >= 0x08) 
	{ 
		lpSubBlock[lpGIFControlParam->wBlockNdx++] = (BYTE)lpGIFControlParam->dwTempCode; 
       
		// 判断是否超出MAX_SUBBLOCK_SIZE 
		if (lpGIFControlParam->wBlockNdx > MAX_SUBBLOCK_SIZE) 
		{ 
			// 判断wByteCnt + 256是否超过MAX_BUFF_SIZE 
			if ((lpGIFControlParam->wByteCnt + 256) >= MAX_BUFF_SIZE) 
			{ 
				// 输出 
				file.Write(lpGIFControlParam->lpDataBuff, 
							lpGIFControlParam->wByteCnt); 
	            lpGIFControlParam->lpEndBuff = lpGIFControlParam->lpDataBuff; 
		        lpGIFControlParam->wByteCnt  = 0; 
			} 
			lpSubBlock[0]           = (BYTE)(lpGIFControlParam->wBlockNdx - 1); 
			memcpy(lpGIFControlParam->lpEndBuff,lpSubBlock,lpGIFControlParam->wBlockNdx); 
			lpGIFControlParam->lpEndBuff   += lpGIFControlParam->wBlockNdx; 
			lpGIFControlParam->wByteCnt    += lpGIFControlParam->wBlockNdx; 
			lpGIFControlParam->wBlockNdx    = 1; 
		} 
		lpGIFControlParam->dwTempCode >>= 8; 
		lpGIFControlParam->byLeftBits  -= 0x08; 
	} 
	 
	// 返回 
	return; 
} 
 
 
/************************************************************************* 
 * 
 * 函数名称: 
 *   ReadGIF() 
 * 
 * 参数: 
 *   CFile& file        - 要读取的文件 
 * 
 * 返回值: 
 *   HDIB               - 成功返回DIB的句柄,否则返回NULL。 
 * 
 * 说明: 
 *   该函数将读取指定的GIF文件。将读取的结果保存在一个未压缩 
 * 编码的DIB对象中。 
 * 
 *************************************************************************/ 
HDIB ReadGIF(LPCTSTR lpszFileName) 
{ 
	 
	// DIB句柄 
	HDIB			   hDIB; 
	 
	// DIB指针 
	LPSTR			   pDIB; 
	 
	// 指向DIB像素的指针 
	LPSTR			   lpDIBBits; 
	 
	// 指向BITMAPINFOHEADER的指针 
	LPBITMAPINFOHEADER lpBIH; 
	 
	// 指向BITMAPINFO的指针 
	LPBITMAPINFO       lpBI;	 
	 
	// GIF文件头 
	GIFHEADER          GIFH; 
	 
	// GIF逻辑屏幕描述块 
	GIFSCRDESC         GIFS; 
	 
	// GIF图像描述块 
	GIFIMAGE           GIFI; 
	 
	// GIF图像控制扩充块 
	GIFCONTROL         GIFC; 
	 
	// GIF图像说明扩充块 
	GIFPLAINTEXT       GIFP; 
	 
	// GIF应用程序扩充块 
	GIFAPPLICATION     GIFA; 
	 
	// GIF编码参数 
	GIFDATAPARAM           GIFDataParam; 
	 
	// 颜色数目 
	WORD               wColors; 
	 
	// 每行字节数 
	WORD               wWidthBytes; 
	 
	// 调色板 
	BYTE               byGIF_Pal[768]; 
	 
	// 16色系统调色板 
	BYTE               bySysPal16[48] = {	0,   0,   0,   0,   0, 128, 
											0, 128,   0,   0, 128, 128, 
										  128,   0,   0, 128,   0, 128, 
										  128, 128,   0, 128, 128, 128, 
										  192, 192, 192,   0,   0, 255, 
											0, 255,   0,   0, 255, 255, 
										  255,   0,   0, 255,   0, 255, 
										  255, 255,   0, 255, 255, 255 
									   }; 
	 
	// DIB大小(字节数) 
	DWORD              dwDIB_Size;	 
	 
	// 调色板大小(字节数) 
	WORD               wPalSize; 
	 
	// 字节变量 
	BYTE               byTemp; 
	 
	// 内存句柄 
	HANDLE			   hSrcBuff; 
	HANDLE             hTemp; 
	 
	// 内存指针 
	LPSTR              lpTemp; 
	 
	// 字变量 
	WORD               wTemp; 
	 
	// 循环变量 
	WORD               wi; 
	 
	// 标签 
	BYTE               byLabel; 
	 
	// 块大小 
	BYTE               byBlockSize; 
 
	// open file 
	CFile file; 
	if (! file.Open(lpszFileName, CFile::modeRead)) 
		return FALSE; 
	 
	// 读取GIF文件头 
	file.Read((LPSTR)&GIFH, sizeof(GIFH)); 
	 
	// 判断是否是GIF文件 
	if (memicmp((LPSTR)GIFH.bySignature,"GIF",3) != 0) 
	{ 
		// 非GIF文件,返回NULL 
		return NULL; 
	} 
	 
	// 判断版本号是否正确 
	if ((memicmp((LPSTR)GIFH.byVersion,"87a",3) != 0) && 
		(memicmp((LPSTR)GIFH.byVersion,"89a",3) != 0)) 
	{ 
		// 不支持该版本,返回NULL 
		return NULL; 
	} 
	 
	// 读取GIF逻辑屏幕描述块 
	file.Read((LPSTR)&GIFS, 7); 
	 
	// 获取调色板的位数 
	GIFDataParam.wBits = (WORD)GIFS.GlobalFlag.PalBits + 1; 
	 
	// 判断是否有全局调色板 
	if (GIFS.GlobalFlag.GlobalPal) 
	{ 
		// 赋初值 
		memset((LPSTR)byGIF_Pal,0,768); 
		 
		// 全局调色板大小 
		wPalSize = 3 * (1 << GIFDataParam.wBits); 
		 
		// 读取全局调色板 
		file.Read((LPSTR)byGIF_Pal,wPalSize); 
	} 
	 
	// 读取下一个字节 
	file.Read((LPSTR)&byTemp,1); 
	 
	// 对每一个描述块循环 
	while(TRUE) 
	{ 
		// 判断是否是图像描述块 
		if (byTemp == 0x2C) 
		{ 
			// 是图像描述块,退出循环 
			break; 
		} 
		 
		// 判断是否是GIF扩展块 
		if (byTemp==0x21) 
		{ 
			// 是GIF扩展块 
			 
			// 分配内存 
			hTemp  = GlobalAlloc(GHND,(DWORD)MAX_BUFF_SIZE); 
			 
			// 锁定内存 
			lpTemp = (LPSTR) GlobalLock(hTemp); 
			 
			// 读取下一个字节 
			file.Read((LPSTR)&byLabel, 1); 
			 
			// 针对各种扩充块,进行分别处理 
			switch(byLabel) 
			{ 
				case 0xF9: 
				{ 
					// 图像控制扩充块 
					file.Read((LPSTR)&GIFC, 6); 
					 
					// 跳出 
					break; 
				} 
				case 0x01: 
				{ 
					// 图像说明扩充块 
					file.Read((LPSTR)&GIFP,sizeof(GIFP)); 
					 
					// 读取扩充块大小 
					file.Read((LPSTR)&byBlockSize,1); 
					 
					// 当byBlockSize > 0时循环读取 
					while(byBlockSize) 
					{ 
						// 读取图像说明扩充块(这里没有进行任何处理) 
						file.Read(lpTemp,byBlockSize); 
						 
						// 读取扩充块大小 
						file.Read((LPSTR)&byBlockSize,1); 
					} 
					 
					// 跳出 
					break; 
				} 
				case 0xFE: 
				{ 
					// 注释说明扩充块 
					 
					// 读取扩充块大小 
					file.Read((LPSTR)&byBlockSize,1); 
					 
					// 当byBlockSize > 0时循环读取 
					while(byBlockSize) 
					{ 
						// 读取注释说明扩充块(这里没有进行任何处理) 
						file.Read(lpTemp,byBlockSize); 
					 
						// 读取扩充块大小 
						file.Read((LPSTR)&byBlockSize,1); 
					} 
					 
					// 跳出 
					break; 
				} 
				case 0xFF: 
				{ 
					// 应用程序扩充块 
					file.Read((LPSTR)&GIFA, sizeof(GIFA)); 
					 
					// 读取扩充块大小 
					file.Read((LPSTR)&byBlockSize,1); 
					 
					// 当byBlockSize > 0时循环读取 
					while(byBlockSize) 
					{ 
						// 读取应用程序扩充块(这里没有进行任何处理) 
						file.Read(lpTemp,byBlockSize); 
						 
						// 读取扩充块大小 
						file.Read((LPSTR)&byBlockSize,1); 
					} 
					 
					// 跳出 
					break; 
				} 
				default: 
				{ 
					// 忽略未知的扩充块 
					 
					// 读取扩充块大小 
					file.Read((LPSTR)&byBlockSize,1); 
					 
					// 当byBlockSize > 0时循环读取 
					while(byBlockSize) 
					{ 
						// 读取未知的扩充块(这里没有进行任何处理) 
						file.Read(lpTemp,byBlockSize); 
						 
						// 读取扩充块大小 
						file.Read((LPSTR)&byBlockSize,1); 
					} 
					 
					// 跳出 
					break; 
				} 
			 
				// 释放内存 
				GlobalUnlock(hTemp); 
				GlobalFree(hTemp); 
			} 
		} 
		 
		// 读取下一个字节 
		file.Read((LPSTR)&byTemp,1); 
	} 
 
	// 读取GIF图像描述块 
	file.Read((LPSTR)&GIFI, 9); 
	 
	// 获取图像宽度 
	GIFDataParam.wWidth         = GIFI.wWidth; 
	 
	// 获取图像高度 
	GIFDataParam.wDepth         = GIFI.wDepth; 
	 
	// 判断是否有区域调色板 
	if (GIFI.LocalFlag.LocalPal) 
	{ 
		// 赋初值 
		memset((LPSTR)byGIF_Pal, 0, 768); 
		 
		// 读取区域调色板位数 
		GIFDataParam.wBits = (WORD)GIFI.LocalFlag.PalBits + 1; 
		 
		// 区域调色板大小 
		wPalSize      = 3 * (1 << GIFDataParam.wBits); 
		 
		// 读取区域调色板 
		file.Read((LPSTR)byGIF_Pal,wPalSize); 
	} 
	 
	// 给GIFDataParam成员赋值 
	GIFDataParam.wBits          = ((GIFDataParam.wBits==1) ? 1 : 
							  (GIFDataParam.wBits<=4) ? 4 : 8); 
	 
	GIFDataParam.wLineBytes     = (WORD)BYTE_WBYTES((DWORD)GIFDataParam.wWidth * 
											   (DWORD)GIFDataParam.wBits); 
	GIFDataParam.bEOF           = FALSE; 
	 
	// 交错方式 
	GIFDataParam.bInterlace     = (GIFI.LocalFlag.Interlace ? TRUE : FALSE); 
	 
	// 每行字节数 
	wWidthBytes			   = (WORD)DWORD_WBYTES((DWORD)GIFDataParam.wWidth * 
								  				(DWORD)GIFDataParam.wBits); 
	 
	// 颜色数目 
	wColors				   = 1 << GIFDataParam.wBits; 
	 
	// 调色板大小 
	wPalSize			   = wColors * sizeof(RGBQUAD); 
	 
	// 计算DIB长度(字节) 
	dwDIB_Size			   = sizeof(BITMAPINFOHEADER) + wPalSize 
							 + GIFDataParam.wDepth * wWidthBytes; 
	 
	// 为DIB分配内存 
	hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwDIB_Size); 
	 
	if (hDIB == 0) 
	{ 
		// 内存分配失败,返回NULL。 
		return NULL; 
	} 
	 
	// 锁定 
	pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB); 
	 
	/////////////////////////////////////////////////////////////////////////// 
	// 设置BITMAPINFOHEADER 
	 
	// 赋值 
	lpBIH = (LPBITMAPINFOHEADER) pDIB; 
	lpBI  = (LPBITMAPINFO) pDIB; 
	 
	// 给lpBIH成员赋值 
	lpBIH->biSize = (DWORD)sizeof(BITMAPINFOHEADER); 
	lpBIH->biWidth = (DWORD)GIFDataParam.wWidth; 
	lpBIH->biHeight = (DWORD)GIFDataParam.wDepth; 
	lpBIH->biPlanes = 1; 
	lpBIH->biBitCount = GIFDataParam.wBits; 
	lpBIH->biCompression = BI_RGB; 
	lpBIH->biSizeImage = (DWORD)wWidthBytes * GIFDataParam.wDepth; 
	lpBIH->biXPelsPerMeter = 0; 
	lpBIH->biYPelsPerMeter = 0; 
	lpBIH->biClrUsed = wColors; 
	lpBIH->biClrImportant = 0; 
	 
	/////////////////////////////////////////////////////////////////////////// 
	// 设置调色板 
	 
	// 判断是否指定全局或区域调色板 
	if (GIFS.GlobalFlag.GlobalPal || GIFI.LocalFlag.LocalPal) 
	{ 
		wTemp = 0; 
		for(wi=0; wibmiColors[wi].rgbRed      = byGIF_Pal[wTemp++]; 
			lpBI->bmiColors[wi].rgbGreen    = byGIF_Pal[wTemp++]; 
			lpBI->bmiColors[wi].rgbBlue     = byGIF_Pal[wTemp++]; 
			lpBI->bmiColors[wi].rgbReserved = 0x00; 
		} 
	} 
	else 
	{ 
		// 没有指定全局和区域调色板,采用系统调色板 
		 
		// 按照颜色数目来分别给调色板赋值 
		switch(wColors) 
		{ 
			case   2: 
			{ 
				// 单色位图 
				 
				lpBI->bmiColors[0].rgbRed          = 0x00; 
				lpBI->bmiColors[0].rgbGreen        = 0x00; 
				lpBI->bmiColors[0].rgbBlue         = 0x00; 
				lpBI->bmiColors[0].rgbReserved     = 0x00; 
				lpBI->bmiColors[1].rgbRed          = 0xFF; 
				lpBI->bmiColors[1].rgbGreen        = 0xFF; 
				lpBI->bmiColors[1].rgbBlue         = 0xFF; 
				lpBI->bmiColors[1].rgbReserved     = 0x00; 
				 
				// 跳出 
				break; 
			} 
			case  16: 
			{ 
				// 16色位图 
				 
				wTemp = 0; 
				for(wi=0;wibmiColors[wi].rgbRed      = bySysPal16[wTemp++]; 
					lpBI->bmiColors[wi].rgbGreen    = bySysPal16[wTemp++]; 
					lpBI->bmiColors[wi].rgbBlue     = bySysPal16[wTemp++]; 
					lpBI->bmiColors[wi].rgbReserved = 0x00; 
				} 
				 
				// 跳出 
				break; 
			} 
			case 256: 
			{ 
				// 256色位图 
				for(wi=0; wibmiColors[wi].rgbRed      = (BYTE)wi; 
					lpBI->bmiColors[wi].rgbGreen    = (BYTE)wi; 
					lpBI->bmiColors[wi].rgbBlue     = (BYTE)wi; 
					lpBI->bmiColors[wi].rgbReserved = 0x00; 
				} 
				 
				// 跳出 
				break; 
			} 
		} 
	} 
	 
	/////////////////////////////////////////////////////////////////////////// 
	// 解码 
 
	// 获取编码数据长度 
	GIFDataParam.dwDataLen  = (DWORD) (file.GetLength() - file.GetPosition()); 
	 
	// 计算内存大小(最大不超过MAX_BUFF_SIZE) 
	GIFDataParam.wMemLen    = ((GIFDataParam.dwDataLen > (DWORD)MAX_BUFF_SIZE) ? 
						  (WORD)MAX_BUFF_SIZE : (WORD)GIFDataParam.dwDataLen); 
	 
	// 分配内存 
	hSrcBuff = GlobalAlloc(GHND, (DWORD)GIFDataParam.wMemLen); 
	 
	// 锁定内存 
	GIFDataParam.lpDataBuff = (LPSTR)GlobalLock(hSrcBuff); 
	 
	// 读取编码数据 
	ReadSrcDataGIF(file,&GIFDataParam.wMemLen,&GIFDataParam.dwDataLen, 
				GIFDataParam.lpDataBuff,&GIFDataParam.bEOF); 
	 
	// 缓冲区起始位置 
	GIFDataParam.lpBgnBuff  = GIFDataParam.lpDataBuff; 
	 
	// 缓冲区中止位置 
	GIFDataParam.lpEndBuff  = GIFDataParam.lpBgnBuff + GIFDataParam.wMemLen; 
	 
	// 计算DIB中像素位置 
	lpDIBBits = (LPSTR) FindDIBBits((LPBYTE)pDIB); 
	 
	// 解码 
	DecodeGIF(file, lpDIBBits, &GIFDataParam, wWidthBytes); 
 
	// 释放内存 
	GlobalUnlock(hSrcBuff); 
	GlobalFree(hSrcBuff); 
	 
	// 返回DIB句柄 
	return hDIB; 
} 
 
 
/************************************************************************* 
 * 
 * 函数名称: 
 *   ReadSrcDataGIF() 
 * 
 * 参数: 
 *   CFile& file			- 源GIF文件 
 *   LPWORD lpwMemLen		- 缓冲区长度(指针) 
 *   LPDWORD lpdwDataLen	- 剩余数据长度(指针) 
 *   LPSTR lpSrcBuff		- 缓冲区指针 
 *	 LPBOOL lpbEOF			- 结束标志 
 * 
 * 返回值: 
 *   无 
 * 
 * 说明: 
 *   该函数用来读取指定GIF文件中的图像编码,每次最多读取MAX_BUFF_SIZE 
 * 字节,是否读完由标志lpbEOF指定。 
 * 
 *************************************************************************/ 
void ReadSrcDataGIF(CFile& file, LPWORD lpwMemLen, LPDWORD lpdwDataLen, 
                        LPSTR lpSrcBuff, LPBOOL lpbEOF) 
{ 
	// 判断数据长度是否仍然大于内存大小 
	if ((*lpdwDataLen) > (DWORD)(*lpwMemLen)) 
	{ 
		// 数据长度大于内存大小,表示没有解码完 
		 
		// 数据长度减内存大小 
		(*lpdwDataLen) -= (DWORD)(*lpwMemLen); 
	} 
	else 
	{ 
		// 数据长度不大于内存大小,表示解码将要完成 
		 
		// 内存大小就是剩余数据长度 
		(*lpwMemLen)    = (WORD)(*lpdwDataLen); 
		 
		// EOF标志设置为TRUE 
		(*lpbEOF)       = TRUE; 
	} 
	 
	// 读取编码数据 
	file.Read(lpSrcBuff, (*lpwMemLen)); 
	 
	// 返回 
	return; 
} 
 
/************************************************************************* 
 * 
 * 函数名称: 
 *   DecodeGIF() 
 * 
 * 参数: 
 *   CFile& file			- 源GIF文件 
 *   LPSTR lpDIBBits		- 指向要保存的DIB图像指针 
 *   LPGIFDATAPARAM lpGIFDataParam	- 指向GIFCONTROLPARAM结构的指针 
 *	 WORD wWidthBytes		- 每行图像字节数 
 * 
 * 返回值: 
 *   无 
 * 
 * 说明: 
 *   该函数对指定GIF_LZW编码数据进行解码。 
 * 
 *************************************************************************/ 
void DecodeGIF(CFile& file, LPSTR lpDIBBits, 
						  LPGIFDATAPARAM lpGIFDataParam,WORD wWidthBytes) 
{ 
	// 指向编码后图像数据的指针 
	BYTE *	lpDst; 
	 
	// 内存分配句柄 
	HANDLE hPrefix; 
	HANDLE hSuffix; 
	HANDLE hStack; 
	HANDLE hImage; 
	 
	// 用于字串表搜索的索引 
	LPWORD lpwPrefix; 
	LPBYTE lpbySuffix; 
	LPBYTE lpbyStack; 
	LPBYTE lpbyStackBgn; 
	 
	// 指向图像当前行解码结果的指针 
	LPSTR  lpImageBgn; 
	 
	// 指向当前编码像素的指针 
	LPSTR  lpImage; 
	 
	// 计算当前数据图像的偏移量 
	DWORD  dwDataNdx; 
	 
	// LZW_CLEAR 
	WORD   wLZW_CLEAR; 
	 
	// LZW_EOI 
	WORD   wLZW_EOI; 
	 
	// LZW_MinCodeLen 
	BYTE   byLZW_MinCodeLen; 
	 
	// 字串表索引 
	WORD   wNowTableNdx; 
	WORD   wTopTableNdx; 
	 
	// 当前图像的行数 
	WORD   wRowNum; 
	 
	// 计数 
	WORD   wWidthCnt; 
	WORD   wBitCnt; 
	WORD   wRowCnt; 
	 
	// 循环变量 
	WORD   wi; 
	 
	// 交错方式存储时每次增加的行数 
	WORD   wIncTable[5]  = { 8,8,4,2,0 };  
	 
	// 交错方式存储时起始行数 
	WORD   wBgnTable[5]  = { 0,4,2,1,0 };  
	 
	// 块大小 
	BYTE   byBlockSize; 
	 
	// 块索引 
	BYTE   byBlockNdx; 
	 
	DWORD  dwData; 
	 
	// 当前编码 
	WORD   wCode; 
	 
	// 上一个编码 
	WORD   wOldCode; 
	 
	// 临时索引 
	WORD   wTempNdx; 
	 
	WORD   wCodeMask[13] = {0x0000, 
							0x0001,0x0003,0x0007,0x000F, 
							0x001F,0x003F,0x007F,0x00FF, 
							0x01FF,0x03FF,0x07FF,0x0FFF 
							}; 
	 
	BYTE   byLeftBits; 
	BYTE   byFirstChar; 
	BYTE   byCode; 
	BYTE   byCurrentBits; 
	BYTE   byPass; 
	 
	// 临时字节变量 
	BYTE   byTempChar; 
	 
	// 给字串表分配内存 
	hPrefix          = GlobalAlloc(GHND,(DWORD)(MAX_TABLE_SIZE<<1)); 
	hSuffix          = GlobalAlloc(GHND,(DWORD)MAX_TABLE_SIZE); 
	hStack           = GlobalAlloc(GHND,(DWORD)MAX_TABLE_SIZE); 
	hImage           = GlobalAlloc(GHND,(DWORD)wWidthBytes); 
	 
	// 锁定内存 
	lpwPrefix        = (LPWORD)GlobalLock(hPrefix); 
	lpbySuffix       = (LPBYTE)GlobalLock(hSuffix); 
	lpbyStack        = (LPBYTE)GlobalLock(hStack); 
	lpbyStackBgn     = lpbyStack; 
	lpImage          = (LPSTR)GlobalLock(hImage); 
	lpImageBgn       = lpImage; 
	 
	// 读取GIF LZW最小编码大小 
	byLZW_MinCodeLen = *lpGIFDataParam->lpBgnBuff++; 
	 
	byCurrentBits    = byLZW_MinCodeLen + (BYTE)0x01; 
	 
	// 计算LZW_CLEAR 
	wLZW_CLEAR       = 1 << byLZW_MinCodeLen; 
	 
	// 计算LZW_EOI 
	wLZW_EOI         = wLZW_CLEAR + 1; 
	 
	// 计算字串表索引 
	wNowTableNdx     = wLZW_CLEAR + 2; 
	wTopTableNdx     = 1 << byCurrentBits; 
	 
	// 赋初值 
	dwData           = 0UL; 
	wBitCnt          = lpGIFDataParam->wBits; 
	wRowNum          = 0; 
	wRowCnt          = 1; 
	wWidthCnt        = 0; 
	wCode            = 0; 
	wOldCode         = 0xFFFF; 
	byBlockSize      = 0x01; 
	byBlockNdx       = 0x00; 
	byLeftBits       = 0x00; 
	byTempChar       = 0x00; 
	byPass           = 0x00; 
	 
	// 读取下一个编码 
	while(byLeftBits < byCurrentBits) 
	{ 
		// 读取下一个字符 
		 
		// 判断是否读完一个数据块 
		if (++byBlockNdx == byBlockSize) 
		{ 
			// 读取下一个数据块 
			byBlockSize = *lpGIFDataParam->lpBgnBuff++; 
			byBlockNdx  = 0x00; 
			 
			// 判断是否读完 
			if ((lpGIFDataParam->lpBgnBuff == lpGIFDataParam->lpEndBuff) && 
			    !lpGIFDataParam->bEOF) 
			{ 
				// 读取下一个数据块 
				ReadSrcDataGIF(file,&lpGIFDataParam->wMemLen, 
							&lpGIFDataParam->dwDataLen, 
							lpGIFDataParam->lpDataBuff,&lpGIFDataParam->bEOF); 
				 
				// 指针重新赋值 
				lpGIFDataParam->lpBgnBuff = lpGIFDataParam->lpDataBuff; 
				lpGIFDataParam->lpEndBuff = lpGIFDataParam->lpBgnBuff + lpGIFDataParam->wMemLen; 
			} 
		} 
		 
		// 下一个字符 
		byCode      = *lpGIFDataParam->lpBgnBuff++; 
		 
		// 移位 
		dwData     |= ((DWORD)byCode << byLeftBits); 
		byLeftBits += 0x08; 
		 
		// 判断是否读完 
		if ((lpGIFDataParam->lpBgnBuff == lpGIFDataParam->lpEndBuff) && 
		    !lpGIFDataParam->bEOF) 
		{ 
			// 读取下一个数据块 
			ReadSrcDataGIF(file,&lpGIFDataParam->wMemLen, 
						&lpGIFDataParam->dwDataLen, 
						lpGIFDataParam->lpDataBuff,&lpGIFDataParam->bEOF); 
			 
			// 指针重新赋值 
			lpGIFDataParam->lpBgnBuff = lpGIFDataParam->lpDataBuff; 
			lpGIFDataParam->lpEndBuff = lpGIFDataParam->lpBgnBuff + lpGIFDataParam->wMemLen; 
		} 
	} 
	 
	wCode       = (WORD)dwData & wCodeMask[byCurrentBits]; 
	dwData    >>= byCurrentBits; 
	byLeftBits -= byCurrentBits; 
	 
	// 解码 
	while(wCode != wLZW_EOI) 
	{ 
		// 当前编码不是LZW_EOI码 
		 
		// 判断是否是LZW_CLEAR码 
		if (wCode == wLZW_CLEAR) 
		{ 
			// 是LZW_CLEAR,清除字串表 
			 
			// 重新初始化字串表 
			for(wi = 0; wi < wLZW_CLEAR; wi++) 
			{ 
				*(lpwPrefix  + wi)  = 0xFFFF; 
				*(lpbySuffix + wi) = (BYTE)wi; 
			} 
			 
			for(wi = wNowTableNdx; wi < MAX_TABLE_SIZE; wi++) 
			{ 
				*(lpwPrefix+wi)  = 0xFFFF; 
				*(lpbySuffix+wi) = 0x00; 
			} 
			 
			byCurrentBits = byLZW_MinCodeLen + (BYTE)0x01; 
			wNowTableNdx  = wLZW_CLEAR + 2; 
			wTopTableNdx  = 1 << byCurrentBits; 
			wOldCode      = 0xFFFF; 
			 
			// 获取下一个编码 
			while(byLeftBits < byCurrentBits) 
			{ 
				// 读取下一个字符 
				 
				// 判断是否读完一个数据块 
				if (++byBlockNdx == byBlockSize) 
				{ 
					// 读取下一个数据块 
					byBlockSize = *lpGIFDataParam->lpBgnBuff++; 
					byBlockNdx  = 0x00; 
					 
					// 判断是否读完 
					if ((lpGIFDataParam->lpBgnBuff == lpGIFDataParam->lpEndBuff) && 
						!lpGIFDataParam->bEOF) 
					{ 
						// 读取下一个数据块 
						ReadSrcDataGIF(file, &lpGIFDataParam->wMemLen, 
									&lpGIFDataParam->dwDataLen, 
									lpGIFDataParam->lpDataBuff, 
									&lpGIFDataParam->bEOF); 
						 
						// 指针重新赋值 
						lpGIFDataParam->lpBgnBuff = lpGIFDataParam->lpDataBuff; 
						lpGIFDataParam->lpEndBuff = lpGIFDataParam->lpBgnBuff + 
											   lpGIFDataParam->wMemLen; 
					} 
				} 
				byCode      = *lpGIFDataParam->lpBgnBuff++; 
				dwData     |= ((DWORD)byCode << byLeftBits); 
				byLeftBits += 0x08; 
				 
				// 判断是否读完 
				if ((lpGIFDataParam->lpBgnBuff == lpGIFDataParam->lpEndBuff) && 
					 !lpGIFDataParam->bEOF) 
				{ 
					// 读取下一个数据块 
					ReadSrcDataGIF(file,&lpGIFDataParam->wMemLen, 
								&lpGIFDataParam->dwDataLen, 
								lpGIFDataParam->lpDataBuff,&lpGIFDataParam->bEOF); 
					 
					// 指针重新赋值 
					lpGIFDataParam->lpBgnBuff = lpGIFDataParam->lpDataBuff; 
					lpGIFDataParam->lpEndBuff = lpGIFDataParam->lpBgnBuff + lpGIFDataParam->wMemLen; 
				} 
			} 
			wCode       = (WORD)dwData & wCodeMask[byCurrentBits]; 
			dwData    >>= byCurrentBits; 
			byLeftBits -= byCurrentBits; 
			 
			// 判断编码是否为LZW_EOI 
			if (wCode!=wLZW_EOI) 
			{ 
				// 这里没有用到lpbyStack[0] 
				lpbyStack  ++; 
				 
				// 将数据压入堆栈 
				while((*(lpwPrefix+wCode)) != 0xFFFF) 
				{ 
					*lpbyStack++ = *(lpbySuffix+wCode); 
					wCode        = *(lpwPrefix+wCode); 
				} 
				*lpbyStack  = *(lpbySuffix+wCode); 
				byFirstChar = *lpbyStack; 
				 
				// 输出数据 
				while(lpbyStack>lpbyStackBgn) 
				{ 
					byTempChar |= (*lpbyStack-- << (8-wBitCnt)); 
					 
					if (wBitCnt==8) 
					{ 
						*lpImage++ = byTempChar; 
						byTempChar = 0x00; 
						wBitCnt    = lpGIFDataParam->wBits; 
					} 
					else 
					{ 
						wBitCnt   += lpGIFDataParam->wBits; 
					} 
					 
					wWidthCnt  ++; 
					 
					if (wWidthCnt==lpGIFDataParam->wWidth) 
					{ 
						if (wBitCnt!=lpGIFDataParam->wBits) 
						{ 
							*lpImage   = byTempChar; 
							byTempChar = 0x00; 
							wBitCnt    = lpGIFDataParam->wBits; 
						} 
						 
						// 图像当前行偏移量 
						dwDataNdx = (DWORD)(lpGIFDataParam->wDepth - 1 - wRowNum) * (DWORD)wWidthBytes; 
						 
						// 图像当前行起始位置 
						lpDst = (BYTE *)lpDIBBits + dwDataNdx; 
						 
						// 赋值 
						memcpy(lpDst, lpImageBgn, wWidthBytes); 
						 
						lpImage   = lpImageBgn; 
						 
						// 判断是否按照交错方式保存 
						if (lpGIFDataParam->bInterlace) 
						{ 
							// 交错方式 
							 
							// 计算下一行的行号 
							wRowNum += wIncTable[byPass]; 
							if (wRowNum >= lpGIFDataParam->wDepth) 
							{ 
								byPass ++; 
								wRowNum = wBgnTable[byPass]; 
							} 
						} 
						else 
						{ 
							// 非交错方式,行号直接加1 
							wRowNum ++; 
						} 
						wWidthCnt = 0; 
					} 
				} 
			} 
		} 
		else 
		{ 
			// 这里没有用到lpbyStack[0] 
			lpbyStack  ++; 
			 
			// 判断字符串是否在字串表中 
			if (wCode < wNowTableNdx) 
			{ 
				// 不在字串表中 
				wTempNdx   = wCode; 
			} 
			else 
			{ 
				// 在字串表中 
				wTempNdx     = wOldCode; 
				*lpbyStack++ = byFirstChar; 
			} 
			 
			// 将数据压入堆栈 
			while((*(lpwPrefix+wTempNdx)) != 0xFFFF) 
			{ 
				*lpbyStack++ = *(lpbySuffix+wTempNdx); 
				wTempNdx     = *(lpwPrefix+wTempNdx); 
			} 
			*lpbyStack  = *(lpbySuffix+wTempNdx); 
			byFirstChar = *lpbyStack; 
			 
			// 将字符串添加到字串表中 
			*(lpwPrefix+wNowTableNdx)  = wOldCode; 
			*(lpbySuffix+wNowTableNdx) = byFirstChar; 
			if (++wNowTableNdx==wTopTableNdx && byCurrentBits<12) 
			{ 
				byCurrentBits ++; 
				wTopTableNdx   = 1 << byCurrentBits; 
			} 
			 
			// 输出数据 
			while(lpbyStack>lpbyStackBgn) 
			{ 
				byTempChar |= (*lpbyStack-- << (8-wBitCnt)); 
				if (wBitCnt==8) 
				{ 
					*lpImage++ = byTempChar; 
					byTempChar = 0x00; 
					wBitCnt    = lpGIFDataParam->wBits; 
				} 
				else 
				{ 
					wBitCnt   += lpGIFDataParam->wBits; 
				} 
				 
				wWidthCnt  ++; 
				if (wWidthCnt==lpGIFDataParam->wWidth) 
				{ 
					if (wBitCnt!=lpGIFDataParam->wBits) 
					{ 
						*lpImage   = byTempChar; 
						byTempChar = 0x00; 
						wBitCnt    = lpGIFDataParam->wBits; 
					} 
					 
					// 图像当前行偏移量 
					dwDataNdx = (DWORD)(lpGIFDataParam->wDepth - 1 - wRowNum) * (DWORD)wWidthBytes; 
					 
					// 图像当前行起始位置 
					lpDst = (BYTE *)lpDIBBits + dwDataNdx; 
					 
					// 赋值 
					memcpy(lpDst, lpImageBgn, wWidthBytes); 
					 
					lpImage   = lpImageBgn; 
					 
					// 判断是否按照交错方式保存 
					if (lpGIFDataParam->bInterlace) 
					{ 
						// 交错方式 
						 
						// 计算下一行的行号 
						wRowNum += wIncTable[byPass]; 
						if (wRowNum >= lpGIFDataParam->wDepth) 
						{ 
							byPass ++; 
							wRowNum = wBgnTable[byPass]; 
						} 
					} 
					else 
					{ 
						// 非交错方式,行号直接加1 
						wRowNum ++; 
					} 
					wWidthCnt = 0; 
				} 
			} 
		} 
		wOldCode = wCode; 
		 
		// 读取下一个编码 
		while(byLeftBits < byCurrentBits) 
		{ 
			// 读取下一个字符 
			 
			// 判断是否读完一个数据块 
			if (++byBlockNdx == byBlockSize) 
			{ 
				// 读取下一个数据块 
				byBlockSize = *lpGIFDataParam->lpBgnBuff++; 
				byBlockNdx  = 0x00; 
				 
				// 判断是否读完 
				if ((lpGIFDataParam->lpBgnBuff == lpGIFDataParam->lpEndBuff) && 
					 !lpGIFDataParam->bEOF) 
				{ 
					// 读取下一个数据块 
					ReadSrcDataGIF(file,&lpGIFDataParam->wMemLen, 
								&lpGIFDataParam->dwDataLen, 
								lpGIFDataParam->lpDataBuff,&lpGIFDataParam->bEOF); 
					 
					// 指针重新赋值 
					lpGIFDataParam->lpBgnBuff = lpGIFDataParam->lpDataBuff; 
					lpGIFDataParam->lpEndBuff = lpGIFDataParam->lpBgnBuff + lpGIFDataParam->wMemLen; 
				} 
			} 
			byCode      = *lpGIFDataParam->lpBgnBuff++; 
			dwData     |= ((DWORD)byCode << byLeftBits); 
			byLeftBits += 0x08; 
			 
			// 判断是否读完 
			if ((lpGIFDataParam->lpBgnBuff == lpGIFDataParam->lpEndBuff) && 
				  !lpGIFDataParam->bEOF) 
			{ 
				// 读取下一个数据块 
				ReadSrcDataGIF(file,&lpGIFDataParam->wMemLen, 
							&lpGIFDataParam->dwDataLen, 
							lpGIFDataParam->lpDataBuff,&lpGIFDataParam->bEOF); 
				 
				// 指针重新赋值 
				lpGIFDataParam->lpBgnBuff = lpGIFDataParam->lpDataBuff; 
				lpGIFDataParam->lpEndBuff = lpGIFDataParam->lpBgnBuff + lpGIFDataParam->wMemLen; 
			} 
		} 
		wCode       = (WORD)dwData & wCodeMask[byCurrentBits]; 
		dwData    >>= byCurrentBits; 
		byLeftBits -= byCurrentBits; 
	} 
	 
	// 释放内存 
	GlobalUnlock(hPrefix); 
	GlobalUnlock(hSuffix); 
	GlobalUnlock(hStack); 
	GlobalFree(hPrefix); 
	GlobalFree(hSuffix); 
	GlobalFree(hStack); 
	 
	// 返回 
	return; 
}