📄 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 + -