?? 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);
// 釋放內存
GlobalFree(hTableNdx);
GlobalFree(hPrefix);
GlobalFree(hSuffix);
// 退出
return;
}
/*************************************************************************
*
* 函數名稱:
* GIF_LZW_WriteCode()
*
* 參數:
* CFile& file - 要保存的文件
* WORD wCode - 要添加的編碼
* LPSTR lpSubBlock - 子塊
* LPBYTE lpbyCurrentBits - 當前位數
* LPGIFC_VAR lpGIFCVar - 指向GIFC_VAR結構的指針
*
* 返回值:
* 無
*
* 說明:
* 該函數用來輸出一個編碼。
*
*************************************************************************/
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;
}
/*************************************************************************
*
* 函數名稱:
* ReadGIF()
*
* 參數:
* CFile& file - 要讀取的文件
*
* 返回值:
* HDIB - 成功返回DIB的句柄,否則返回NULL。
*
* 說明:
* 該函數將讀取指定的GIF文件。將讀取的結果保存在一個未壓縮
* 編碼的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圖像控制擴充塊
GIFCONTROL GIFC;
// GIF圖像說明擴充塊
GIFPLAINTEXT GIFP;
// GIF應用程序擴充塊
GIFAPPLICATION GIFA;
// GIF編碼參數
GIFD_VAR GIFDVar;
// 顏色數目
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;
// 讀取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);
// 獲取調色板的位數
GIFDVar.wBits = (WORD)GIFS.GlobalFlag.PalBits + 1;
// 判斷是否有全局調色板
if (GIFS.GlobalFlag.GlobalPal)
{
// 賦初值
memset((LPSTR)byGIF_Pal,0,768);
// 全局調色板大小
wPalSize = 3 * (1 << GIFDVar.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);
// 獲取圖像寬度
GIFDVar.wWidth = GIFI.wWidth;
// 獲取圖像高度
GIFDVar.wDepth = GIFI.wDepth;
// 判斷是否有區域調色板
if (GIFI.LocalFlag.LocalPal)
{
// 賦初值
memset((LPSTR)byGIF_Pal, 0, 768);
// 讀取區域調色板位數
GIFDVar.wBits = (WORD)GIFI.LocalFlag.PalBits + 1;
// 區域調色板大小
wPalSize = 3 * (1 << GIFDVar.wBits);
// 讀取區域調色板
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);
// 每行字節數
wWidthBytes = (WORD)DWORD_WBYTES((DWORD)GIFDVar.wWidth *
(DWORD)GIFDVar.wBits);
// 顏色數目
wColors = 1 << GIFDVar.wBits;
// 調色板大小
wPalSize = wColors * sizeof(RGBQUAD);
// 計算DIB長度(字節)
dwDIB_Size = sizeof(BITMAPINFOHEADER) + wPalSize
+ GIFDVar.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)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;
///////////////////////////////////////////////////////////////////////////
// 設置調色板
// 判斷是否指定全局或區域調色板
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
{
// 沒有指定全局和區域調色板,采用系統調色板
// 按照顏色數目來分別給調色板賦值
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;
}
}
}
///////////////////////////////////////////////////////////////////////////
// 解碼
// 獲取編碼數據長度
GIFDVar.dwDataLen = (DWORD) (file.GetLength() - file.GetPosition());
// 計算內存大小(最大不超過MAX_BUFF_SIZE)
GIFDVar.wMemLen = ((GIFDVar.dwDataLen > (DWORD)MAX_BUFF_SIZE) ?
(WORD)MAX_BUFF_SIZE : (WORD)GIFDVar.dwDataLen);
// 分配內存
hSrcBuff = GlobalAlloc(GHND, (DWORD)GIFDVar.wMemLen);
// 鎖定內存
GIFDVar.lpDataBuff = (LPSTR)GlobalLock(hSrcBuff);
// 讀取編碼數據
ReadSrcData(file,&GIFDVar.wMemLen,&GIFDVar.dwDataLen,
GIFDVar.lpDataBuff,&GIFDVar.bEOF);
// 緩沖區起始位置
GIFDVar.lpBgnBuff = GIFDVar.lpDataBuff;
// 緩沖區中止位置
GIFDVar.lpEndBuff = GIFDVar.lpBgnBuff + GIFDVar.wMemLen;
// 計算DIB中像素位置
lpDIBBits = (LPSTR) FindDIBBits(pDIB);
// 解碼
DecodeGIF_LZW(file, lpDIBBits, &GIFDVar, wWidthBytes);
// 釋放內存
GlobalUnlock(hSrcBuff);
GlobalFree(hSrcBuff);
// 返回DIB句柄
return hDIB;
}
/*************************************************************************
*
* 函數名稱:
* ReadSrcData()
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -