📄 coding.cpp
字号:
// 用于字串表搜索的索引
LPWORD lpwPrefix;
LPBYTE lpbySuffix;
// 指向当前编码像素的指针
LPBYTE 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 = (lpGIFCVar->wBits>1) ? lpGIFCVar->wBits : 0x02;
// 写GIF LZW最小代码大小
file.Write(&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 + 0x01;
wNowTableNdx = wLZW_CLEAR + 2;
wTopTableNdx = 1 << byCurrentBits;
for(wi = 0; wi < MAX_HASH_SIZE; wi++)
{
// 初始化为0xFFFF
*(lpwTableNdx + wi) = 0xFFFF;
}
// 输出LZW_CLEAR
OutputCode(file, wLZW_CLEAR, bySubBlock, &byCurrentBits, lpGIFCVar);
// 逐行编码
for(wi=0; wi < lpGIFCVar->wDepth; wi++)
{
// 计算当前偏移量
dwDataNdx = (DWORD)(lpGIFCVar->wDepth - 1 - wRowNum) * (DWORD)wWidthBytes;
// 指向当前行图像的指针
lpImage = lpDIBBits + dwDataNdx;
wWidthCnt = 0;
wShiftBits = 8 - lpGIFCVar->wBits;
byMask = (lpGIFCVar->wBits == 1) ? 0x80 : 0xF0;
if (bStart)
{
// 判断是否是256色位图(一个像素一字节)
if (lpGIFCVar->wBits == 8)
{
// 256色,直接赋值即可
byTemp = *lpImage++;
}
else
{
// 非256色,需要移位获取像素值
wShiftBits = 8 - lpGIFCVar->wBits;
byMask = (lpGIFCVar->wBits == 1) ? 0x80 : 0xF0;
byTemp = (*lpImage & byMask) >> wShiftBits;
byMask >>= lpGIFCVar->wBits;
wShiftBits -= lpGIFCVar->wBits;
}
wPrefix = (WORD)byTemp;
bStart = FALSE;
wWidthCnt++;
}
// 每行编码
while(wWidthCnt < lpGIFCVar->wWidth)
{
// 判断是否是256色位图(一个像素一字节)
if (lpGIFCVar->wBits == 8)
{
// 256色,直接赋值即可
byTemp = *lpImage++;
}
else
{
// 非256色,需要移位获取像素值
byChar = *lpImage;
byTemp = (byChar & byMask) >> wShiftBits;
if (wShiftBits)
{
byMask >>= lpGIFCVar->wBits;
wShiftBits -= lpGIFCVar->wBits;
}
else
{
wShiftBits = 8 - lpGIFCVar->wBits;
byMask = (lpGIFCVar->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
{
// 新字符串
// 输出该编码
OutputCode(file, wPrefix, bySubBlock, &byCurrentBits, lpGIFCVar);
// 将该新字符串添加到字串表中
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
OutputCode(file, wLZW_CLEAR, bySubBlock, &byCurrentBits, lpGIFCVar);
// 重新初始化字串表
byCurrentBits = byLZW_MinCodeLen + 0x01;
wLZW_CLEAR = 1 << byLZW_MinCodeLen;
wLZW_EOI = wLZW_CLEAR + 1;
wNowTableNdx = wLZW_CLEAR + 2;
wTopTableNdx = 1 << byCurrentBits;
for(wj = 0; wj < MAX_HASH_SIZE; wj++)
{
// 初始化为0xFFFF
*(lpwTableNdx+wj) = 0xFFFF;
}
}
}
wPrefix = (WORD)bySuffix;
}
}
// 判断是否是交错方式
if (bInterlace)
{
// 交错方式,计算下一行位置
wRowNum += wIncTable[byPass];
if (wRowNum >= lpGIFCVar->wDepth)
{
byPass++;
wRowNum = wBgnTable[byPass];
}
}
else
{
// 非交错方式,直接将行数加一即可
wRowNum ++;
}
}
// 输出当前编码
OutputCode(file, wPrefix, bySubBlock, &byCurrentBits, lpGIFCVar);
// 输出LZW_EOI
OutputCode(file, wLZW_EOI, bySubBlock, &byCurrentBits, lpGIFCVar);
if (lpGIFCVar->byLeftBits)
{
// 加入该字符
bySubBlock[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;
}
bySubBlock[0] = (lpGIFCVar->wBlockNdx - 1);
memcpy(lpGIFCVar->lpEndBuff, bySubBlock, lpGIFCVar->wBlockNdx);
lpGIFCVar->lpEndBuff += lpGIFCVar->wBlockNdx;
lpGIFCVar->wByteCnt += lpGIFCVar->wBlockNdx;
lpGIFCVar->wBlockNdx = 1;
}
lpGIFCVar->dwTempCode = 0UL;
lpGIFCVar->byLeftBits = 0x00;
}
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] = lpGIFCVar->wBlockNdx - 1;
memcpy(lpGIFCVar->lpEndBuff, 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;
}
/*************************************************************************
*
* 函数名称:
* OutputCode()
*
* 参数:
* CFile& file - 要保存的文件
* WORD wCode - 要添加的编码
* LPBYTE lpbySubBlock - 子块
* LPBYTE lpbyCurrentBits - 当前位数
* LPGIFC_VAR lpGIFCVar - 指向GIFC_VAR结构的指针
*
* 返回值:
* 无
*
* 说明:
* 该函数用来输出一个编码。
*
*************************************************************************/
void CCoding::OutputCode(CFile &file, WORD wCode, LPBYTE lpbySubBlock, LPBYTE lpbyCurrentBits, LPGIFC_VAR lpGIFCVar)
{
// 输出该编码
lpGIFCVar->dwTempCode |= ((DWORD)wCode << lpGIFCVar->byLeftBits);
lpGIFCVar->byLeftBits += (*lpbyCurrentBits);
while(lpGIFCVar->byLeftBits >= 0x08)
{
lpbySubBlock[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;
}
lpbySubBlock[0] = lpGIFCVar->wBlockNdx - 1;
memcpy(lpGIFCVar->lpEndBuff, lpbySubBlock, lpGIFCVar->wBlockNdx);
lpGIFCVar->lpEndBuff += lpGIFCVar->wBlockNdx;
lpGIFCVar->wByteCnt += lpGIFCVar->wBlockNdx;
lpGIFCVar->wBlockNdx = 1;
}
lpGIFCVar->dwTempCode >>= 8;
lpGIFCVar->byLeftBits -= 0x08;
}
// 返回
return;
}
/*************************************************************************
*
* 函数名称:
* GIFToDIB()
*
* 参数:
* CFile& file - 要读取的文件
*
* 返回值:
* HDIB - 成功返回DIB的句柄,否则返回NULL。
*
* 说明:
* 该函数读取GIF文件到DIB
*
*************************************************************************/
HDIB CCoding::GIFToDIB(CFile &file)
{
// 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;
// 内存指针
LPBYTE lpTemp;
// 字变量
WORD wTemp;
// 循环变量
WORD wi;
// 标签
BYTE byLabel;
// 块大小
BYTE byBlockSize;
// 读取GIF文件头
file.Read((LPBYTE)&GIFH, sizeof(GIFH));
// 判断是否是GIF文件
if (memicmp((LPBYTE)GIFH.bySignature,"GIF",3) != 0)
{
// 非GIF文件,返回NULL
return NULL;
}
// 判断版本号是否正确
if ((memicmp((LPBYTE)GIFH.byVersion,"87a",3) != 0) &&
(memicmp((LPBYTE)GIFH.byVersion,"89a",3) != 0))
{
// 不支持该版本,返回NULL
return NULL;
}
// 读取GIF逻辑屏幕描述块
file.Read((LPBYTE)&GIFS, 7);
// 获取调色板的位数
GIFDVar.wBits = (WORD)GIFS.GlobalFlag.PalBits + 1;
// 判断是否有全局调色板
if (GIFS.GlobalFlag.GlobalPal)
{
// 赋初值
memset((LPBYTE)byGIF_Pal,0,768);
// 全局调色板大小
wPalSize = 3 * (1 << GIFDVar.wBits);
// 读取全局调色板
file.Read((LPBYTE)byGIF_Pal,wPalSize);
}
// 读取下一个字节
file.Read((LPBYTE)&byTemp,1);
// 对每一个描述块循环
while(TRUE)
{
// 判断是否是图像描述块
if (byTemp == 0x2C)
{
// 是图像描述块,退出循环
break;
}
// 判断是否是GIF扩展块
if (byTemp==0x21)
{
// 是GIF扩展块
// 分配内存
hTemp = GlobalAlloc(GHND, (DWORD)MAX_BUFF_SIZE);
// 锁定内存
lpTemp = (LPBYTE) GlobalLock(hTemp);
// 读取下一个字节
file.Read((LPBYTE)&byLabel, 1);
// 针对各种扩充块,进行分别处理
switch(byLabel)
{
case 0xF9:
{
// 图像控制扩充块
file.Read((LPBYTE)&GIFC, 6);
// 跳出
break;
}
case 0x01:
{
// 图像说明扩充块
file.Read((LPBYTE)&GIFP, sizeof(GIFP));
// 读取扩充块大小
file.Read((LPBYTE)&byBlockSize, 1);
// 当byBlockSize > 0时循环读取
while(byBlockSize)
{
// 读取图像说明扩充块(这里没有进行任何处理)
file.Read(lpTemp, byBlockSize);
// 读取扩充块大小
file.Read((LPBYTE)&byBlockSize, 1);
}
// 跳出
break;
}
case 0xFE:
{
// 注释说明扩充块
// 读取扩充块大小
file.Read((LPBYTE)&byBlockSize, 1);
// 当byBlockSize > 0时循环读取
while(byBlockSize)
{
// 读取注释说明扩充块(这里没有进行任何处理)
file.Read(lpTemp, byBlockSize);
// 读取扩充块大小
file.Read((LPBYTE)&byBlockSize, 1);
}
// 跳出
break;
}
case 0xFF:
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -