?? gifapi.cpp
字號:
if (lpGIFCVar->wBlockNdx > 1)
{
// 判斷wByteCnt + 256是否超過MAX_BUFF_SIZE
if ((lpGIFCVar->wByteCnt + 256) >= MAX_BUFF_SIZE)
{
// 輸出
file.Write(lpGIFCVar->lpDataBuff,
lpGIFCVar->wByteCnt);
lpGIFCVar->lpEndBuff = lpGIFCVar->lpDataBuff;
lpGIFCVar->wByteCnt = 0;
}
bySubBlock[0] = (BYTE)(lpGIFCVar->wBlockNdx - 1);
memcpy(lpGIFCVar->lpEndBuff,(LPSTR)bySubBlock,lpGIFCVar->wBlockNdx);
lpGIFCVar->lpEndBuff += lpGIFCVar->wBlockNdx;
lpGIFCVar->wByteCnt += lpGIFCVar->wBlockNdx;
lpGIFCVar->wBlockNdx = 1;
}
// 解除鎖定
GlobalUnlock(hTableNdx);
GlobalUnlock(hPrefix);
GlobalUnlock(hSuffix);
// 釋放內(nèi)存
GlobalFree(hTableNdx);
GlobalFree(hPrefix);
GlobalFree(hSuffix);
// 退出
return;
}
/*************************************************************************
*
* 函數(shù)名稱:
* GIF_LZW_WriteCode()
*
* 參數(shù):
* CFile& file - 要保存的文件
* WORD wCode - 要添加的編碼
* LPSTR lpSubBlock - 子塊
* LPBYTE lpbyCurrentBits - 當(dāng)前位數(shù)
* LPGIFC_VAR lpGIFCVar - 指向GIFC_VAR結(jié)構(gòu)的指針
*
* 返回值:
* 無
*
* 說明:
* 該函數(shù)用來輸出一個編碼。
*
*************************************************************************/
void WINAPI GIF_LZW_WriteCode(CFile& file, WORD wCode, LPSTR lpSubBlock,
LPBYTE lpbyCurrentBits,LPGIFC_VAR lpGIFCVar)
{
// 輸出該編碼
lpGIFCVar->dwTempCode |= ((DWORD)wCode << lpGIFCVar->byLeftBits);
lpGIFCVar->byLeftBits += (*lpbyCurrentBits);
while(lpGIFCVar->byLeftBits >= 0x08)
{
lpSubBlock[lpGIFCVar->wBlockNdx++] = (BYTE)lpGIFCVar->dwTempCode;
// 判斷是否超出MAX_SUBBLOCK_SIZE
if (lpGIFCVar->wBlockNdx > MAX_SUBBLOCK_SIZE)
{
// 判斷wByteCnt + 256是否超過MAX_BUFF_SIZE
if ((lpGIFCVar->wByteCnt + 256) >= MAX_BUFF_SIZE)
{
// 輸出
file.Write(lpGIFCVar->lpDataBuff,
lpGIFCVar->wByteCnt);
lpGIFCVar->lpEndBuff = lpGIFCVar->lpDataBuff;
lpGIFCVar->wByteCnt = 0;
}
lpSubBlock[0] = (BYTE)(lpGIFCVar->wBlockNdx - 1);
memcpy(lpGIFCVar->lpEndBuff,lpSubBlock,lpGIFCVar->wBlockNdx);
lpGIFCVar->lpEndBuff += lpGIFCVar->wBlockNdx;
lpGIFCVar->wByteCnt += lpGIFCVar->wBlockNdx;
lpGIFCVar->wBlockNdx = 1;
}
lpGIFCVar->dwTempCode >>= 8;
lpGIFCVar->byLeftBits -= 0x08;
}
// 返回
return;
}
/*************************************************************************
*
* 函數(shù)名稱:
* ReadGIF()
*
* 參數(shù):
* CFile& file - 要讀取的文件
*
* 返回值:
* HDIB - 成功返回DIB的句柄,否則返回NULL。
*
* 說明:
* 該函數(shù)將讀取指定的GIF文件。將讀取的結(jié)果保存在一個未壓縮
* 編碼的DIB對象中。
*
*************************************************************************/
HDIB WINAPI ReadGIF(CFile& file)
{
// 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圖像控制擴(kuò)充塊
GIFCONTROL GIFC;
// GIF圖像說明擴(kuò)充塊
GIFPLAINTEXT GIFP;
// GIF應(yīng)用程序擴(kuò)充塊
GIFAPPLICATION GIFA;
// GIF編碼參數(shù)
GIFD_VAR GIFDVar;
// 顏色數(shù)目
WORD wColors;
// 每行字節(jié)數(shù)
WORD wWidthBytes;
// 調(diào)色板
BYTE byGIF_Pal[768];
// 16色系統(tǒng)調(diào)色板
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大小(字節(jié)數(shù))
DWORD dwDIB_Size;
// 調(diào)色板大小(字節(jié)數(shù))
WORD wPalSize;
// 字節(jié)變量
BYTE byTemp;
// 內(nèi)存句柄
HANDLE hSrcBuff;
HANDLE hTemp;
// 內(nèi)存指針
LPSTR lpTemp;
// 字變量
WORD wTemp;
// 循環(huán)變量
WORD wi;
// 標(biāo)簽
BYTE byLabel;
// 塊大小
BYTE byBlockSize;
// 讀取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);
// 獲取調(diào)色板的位數(shù)
GIFDVar.wBits = (WORD)GIFS.GlobalFlag.PalBits + 1;
// 判斷是否有全局調(diào)色板
if (GIFS.GlobalFlag.GlobalPal)
{
// 賦初值
memset((LPSTR)byGIF_Pal,0,768);
// 全局調(diào)色板大小
wPalSize = 3 * (1 << GIFDVar.wBits);
// 讀取全局調(diào)色板
file.Read((LPSTR)byGIF_Pal,wPalSize);
}
// 讀取下一個字節(jié)
file.Read((LPSTR)&byTemp,1);
// 對每一個描述塊循環(huán)
while(TRUE)
{
// 判斷是否是圖像描述塊
if (byTemp == 0x2C)
{
// 是圖像描述塊,退出循環(huán)
break;
}
// 判斷是否是GIF擴(kuò)展塊
if (byTemp==0x21)
{
// 是GIF擴(kuò)展塊
// 分配內(nèi)存
hTemp = GlobalAlloc(GHND,(DWORD)MAX_BUFF_SIZE);
// 鎖定內(nèi)存
lpTemp = (LPSTR) GlobalLock(hTemp);
// 讀取下一個字節(jié)
file.Read((LPSTR)&byLabel, 1);
// 針對各種擴(kuò)充塊,進(jìn)行分別處理
switch(byLabel)
{
case 0xF9:
{
// 圖像控制擴(kuò)充塊
file.Read((LPSTR)&GIFC, 6);
// 跳出
break;
}
case 0x01:
{
// 圖像說明擴(kuò)充塊
file.Read((LPSTR)&GIFP,sizeof(GIFP));
// 讀取擴(kuò)充塊大小
file.Read((LPSTR)&byBlockSize,1);
// 當(dāng)byBlockSize > 0時循環(huán)讀取
while(byBlockSize)
{
// 讀取圖像說明擴(kuò)充塊(這里沒有進(jìn)行任何處理)
file.Read(lpTemp,byBlockSize);
// 讀取擴(kuò)充塊大小
file.Read((LPSTR)&byBlockSize,1);
}
// 跳出
break;
}
case 0xFE:
{
// 注釋說明擴(kuò)充塊
// 讀取擴(kuò)充塊大小
file.Read((LPSTR)&byBlockSize,1);
// 當(dāng)byBlockSize > 0時循環(huán)讀取
while(byBlockSize)
{
// 讀取注釋說明擴(kuò)充塊(這里沒有進(jìn)行任何處理)
file.Read(lpTemp,byBlockSize);
// 讀取擴(kuò)充塊大小
file.Read((LPSTR)&byBlockSize,1);
}
// 跳出
break;
}
case 0xFF:
{
// 應(yīng)用程序擴(kuò)充塊
file.Read((LPSTR)&GIFA, sizeof(GIFA));
// 讀取擴(kuò)充塊大小
file.Read((LPSTR)&byBlockSize,1);
// 當(dāng)byBlockSize > 0時循環(huán)讀取
while(byBlockSize)
{
// 讀取應(yīng)用程序擴(kuò)充塊(這里沒有進(jìn)行任何處理)
file.Read(lpTemp,byBlockSize);
// 讀取擴(kuò)充塊大小
file.Read((LPSTR)&byBlockSize,1);
}
// 跳出
break;
}
default:
{
// 忽略未知的擴(kuò)充塊
// 讀取擴(kuò)充塊大小
file.Read((LPSTR)&byBlockSize,1);
// 當(dāng)byBlockSize > 0時循環(huán)讀取
while(byBlockSize)
{
// 讀取未知的擴(kuò)充塊(這里沒有進(jìn)行任何處理)
file.Read(lpTemp,byBlockSize);
// 讀取擴(kuò)充塊大小
file.Read((LPSTR)&byBlockSize,1);
}
// 跳出
break;
}
// 釋放內(nèi)存
GlobalUnlock(hTemp);
GlobalFree(hTemp);
}
}
// 讀取下一個字節(jié)
file.Read((LPSTR)&byTemp,1);
}
// 讀取GIF圖像描述塊
file.Read((LPSTR)&GIFI, 9);
// 獲取圖像寬度
GIFDVar.wWidth = GIFI.wWidth;
// 獲取圖像高度
GIFDVar.wDepth = GIFI.wDepth;
// 判斷是否有區(qū)域調(diào)色板
if (GIFI.LocalFlag.LocalPal)
{
// 賦初值
memset((LPSTR)byGIF_Pal, 0, 768);
// 讀取區(qū)域調(diào)色板位數(shù)
GIFDVar.wBits = (WORD)GIFI.LocalFlag.PalBits + 1;
// 區(qū)域調(diào)色板大小
wPalSize = 3 * (1 << GIFDVar.wBits);
// 讀取區(qū)域調(diào)色板
file.Read((LPSTR)byGIF_Pal,wPalSize);
}
// 給GIFDVar成員賦值
GIFDVar.wBits = ((GIFDVar.wBits==1) ? 1 :
(GIFDVar.wBits<=4) ? 4 : 8);
GIFDVar.wLineBytes = (WORD)BYTE_WBYTES((DWORD)GIFDVar.wWidth *
(DWORD)GIFDVar.wBits);
GIFDVar.bEOF = FALSE;
// 交錯方式
GIFDVar.bInterlace = (GIFI.LocalFlag.Interlace ? TRUE : FALSE);
// 每行字節(jié)數(shù)
wWidthBytes = (WORD)DWORD_WBYTES((DWORD)GIFDVar.wWidth *
(DWORD)GIFDVar.wBits);
// 顏色數(shù)目
wColors = 1 << GIFDVar.wBits;
// 調(diào)色板大小
wPalSize = wColors * sizeof(RGBQUAD);
// 計算DIB長度(字節(jié))
dwDIB_Size = sizeof(BITMAPINFOHEADER) + wPalSize
+ GIFDVar.wDepth * wWidthBytes;
// 為DIB分配內(nèi)存
hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwDIB_Size);
if (hDIB == 0)
{
// 內(nèi)存分配失敗,返回NULL。
return NULL;
}
// 鎖定
pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
///////////////////////////////////////////////////////////////////////////
// 設(shè)置BITMAPINFOHEADER
// 賦值
lpBIH = (LPBITMAPINFOHEADER) pDIB;
lpBI = (LPBITMAPINFO) pDIB;
// 給lpBIH成員賦值
lpBIH->biSize = (DWORD)sizeof(BITMAPINFOHEADER);
lpBIH->biWidth = (DWORD)GIFDVar.wWidth;
lpBIH->biHeight = (DWORD)GIFDVar.wDepth;
lpBIH->biPlanes = 1;
lpBIH->biBitCount = GIFDVar.wBits;
lpBIH->biCompression = BI_RGB;
lpBIH->biSizeImage = (DWORD)wWidthBytes * GIFDVar.wDepth;
lpBIH->biXPelsPerMeter = 0;
lpBIH->biYPelsPerMeter = 0;
lpBIH->biClrUsed = wColors;
lpBIH->biClrImportant = 0;
///////////////////////////////////////////////////////////////////////////
// 設(shè)置調(diào)色板
// 判斷是否指定全局或區(qū)域調(diào)色板
if (GIFS.GlobalFlag.GlobalPal || GIFI.LocalFlag.LocalPal)
{
wTemp = 0;
for(wi=0; wi<wColors; wi++)
{
lpBI->bmiColors[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
{
// 沒有指定全局和區(qū)域調(diào)色板,采用系統(tǒng)調(diào)色板
// 按照顏色數(shù)目來分別給調(diào)色板賦值
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;wi<wColors;wi++)
{
lpBI->bmiColors[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; wi<wColors; wi++)
{
lpBI->bmiColors[wi].rgbRed = (BYTE)wi;
lpBI->bmiColors[wi].rgbGreen = (BYTE)wi;
lpBI->bmiColors[wi].rgbBlue = (BYTE)wi;
lpBI->bmiColors[wi].rgbReserved = 0x00;
}
// 跳出
break;
}
}
}
///////////////////////////////////////////////////////////////////////////
// 解碼
// 獲取編碼數(shù)據(jù)長度
GIFDVar.dwDataLen = (DWORD) (file.GetLength() - file.GetPosition());
// 計算內(nèi)存大?。ㄗ畲蟛怀^MAX_BUFF_SIZE)
GIFDVar.wMemLen = ((GIFDVar.dwDataLen > (DWORD)MAX_BUFF_SIZE) ?
(WORD)MAX_BUFF_SIZE : (WORD)GIFDVar.dwDataLen);
// 分配內(nèi)存
hSrcBuff = GlobalAlloc(GHND, (DWORD)GIFDVar.wMemLen);
// 鎖定內(nèi)存
GIFDVar.lpDataBuff = (LPSTR)GlobalLock(hSrcBuff);
// 讀取編碼數(shù)據(jù)
ReadSrcData(file,&GIFDVar.wMemLen,&GIFDVar.dwDataLen,
GIFDVar.lpDataBuff,&GIFDVar.bEOF);
// 緩沖區(qū)起始位置
GIFDVar.lpBgnBuff = GIFDVar.lpDataBuff;
// 緩沖區(qū)中止位置
GIFDVar.lpEndBuff = GIFDVar.lpBgnBuff + GIFDVar.wMemLen;
// 計算DIB中像素位置
lpDIBBits = (LPSTR) FindDIBBits(pDIB);
// 解碼
DecodeGIF_LZW(file, lpDIBBits, &GIFDVar, wWidthBytes);
// 釋放內(nèi)存
GlobalUnlock(hSrcBuff);
GlobalFree(hSrcBuff);
// 返回DIB句柄
return hDIB;
}
/*************************************************************************
*
* 函數(shù)名稱:
* ReadSrcData()
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -