📄 coding.cpp
字号:
if (iMap[k] == j)
{
// 映射到节点j+1
iMap[k] = j + 1;
}
else if (iMap[k] == j + 1)
{
// 映射到节点j
iMap[k] = j;
}
}
}
else
{
// 退出循环
break;
}
}
}
//////////////////////////////////////////////////////////
// 对DIB进行编码压缩
// 位掩码
unsigned char Mask[8] = {128, 64, 32, 16, 8, 4, 2, 1};
CString strTemp = "";
// 打开文件
CFile file;
file.Open(strPath, CFile::modeCreate | CFile::modeReadWrite);
// 对各像素进行编码
for (i = 0; i < lHeight; i ++)
{
for (j = 0; j < lLineBytes; j ++)
{
unsigned char V = *((unsigned char *)lpDIBBits + lLineBytes * i + j);
strTemp += m_strCode[V];
int len = strTemp.GetLength();
int loop = 0;
// 保存编码后的数据
do{
unsigned char T = 0;
for (k = 0; k < min(8, strTemp.GetLength()); k++)
{
if (strTemp.Mid(k, 1) == "1")
T |= Mask[k];
}
file.Write(&T, 1);
loop++;
len -= 8;
if (strTemp.GetLength() < 8)
break;
else
strTemp = strTemp.Right(strTemp.GetLength() - 8);
}while (len >= 8);
}
}
// 关闭文件
file.Close();
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 恢复光标
EndWaitCursor();
// 返回TRUE
return TRUE;
}
/*************************************************************************
*
* 函数名称:
* Shannon_Fannon()
*
* 参数:
* HDIB hDIB - 待编码DIB句柄
* CString strPath - 要装载的文件路径
*
* 返回值:
* BOOL - 成功返回True,否则返回False。
*
* 说明:
* 该函数对指定DIB位图进行仙农-弗诺编码
*
*************************************************************************/
BOOL CCoding::Shannon_Fannon(HDIB hDIB, CString strPath)
{
// 字符串变量
CString str;
// 中间变量
LONG iTemp;
// 当前编码区间的频率和
FLOAT fTotal = 0;
// 计数(编码完成的个数)
LONG iCount = 0;
// 频率和
FLOAT fSum;
// 起始位置
LONG iStart;
// 指向布尔型数组的指针
BOOL bFinished[256];
// 循环变量
LONG i;
LONG j;
LONG k;
// 灰度计数
int nNs[256];
// 灰度概率分布
float fPs[256];
// 映射关系
int iMap[256];
// Huffman编码
CString m_strCode [256];
// 变量初始化
memset(nNs, 0, sizeof(nNs));
// 指向DIB的指针
LPBYTE lpDIB;
// 指向DIB象素指针
LPBYTE lpDIBBits;
// 锁定DIB
lpDIB = (LPBYTE) ::GlobalLock((HGLOBAL) hDIB);
// 找到DIB图像象素起始位置
lpDIBBits = m_clsDIB.FindDIBBits(lpDIB);
// 判断是否是24-bpp位图
if (m_clsDIB.DIBBitCount(lpDIB) != 24)
{
// 提示用户
MessageBox("请先将其转换为24位色位图,再进行处理!", "系统提示" , MB_ICONINFORMATION | MB_OK);
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 返回
return FALSE;
}
// 更改光标形状
BeginWaitCursor();
//////////////////////////////////////////////////////////
// 计算灰度概率分布
// DIB的宽度
LONG lWidth = m_clsDIB.DIBWidth(lpDIB);
// DIB的高度
LONG lHeight = m_clsDIB.DIBHeight(lpDIB);
// 计算图像每行的字节数
LONG lLineBytes = WIDTHBYTES(lWidth * 24);
// 对各像素进行灰度分布统计
for (i = 0; i < lHeight; i ++)
{
for (j = 0; j < lLineBytes; j ++)
{
// 对各像素进行灰度统计
unsigned char V = *((unsigned char *)lpDIBBits + lLineBytes * i + j);
nNs[V]++;
}
}
// 计算灰度分布密度
for(i = 0; i < 256; i++)
fPs[i] = nNs[i] / (lHeight * lLineBytes * 1.0f);
// 初始化
for (i = 0; i < 256; i ++)
{
// 初始化映射关系
iMap[i] = i;
// 初始化为FALSE
bFinished[i] = FALSE;
// 计算fTotal
fTotal += fPs[i];
}
// 用冒泡法对fPs[]进行排序
for (j = 0; j < 256 - 1; j ++)
{
for (i = 0; i < 256 - j - 1; i ++)
{
if (fPs[i] > fPs[i + 1])
{
// 互换
float fTemp = fPs[i];
fPs[i] = fPs[i + 1];
fPs[i + 1] = fTemp;
// 更新映射关系
iTemp = iMap[i];
iMap[i] = iMap[i+1];
iMap[i+1] = iTemp;
}
}
}
//////////////////////////////////////////////////////////
// 计算仙农-弗诺编码表
// 寻找第一个不为0的概率灰度级
for (iStart = 0; iStart < 256 - 1; iStart++)
{
// 判断概率是否大于0
if (fPs[iStart] > 0)
break;
}
// 初始化变量
fSum = 0;
str = "1";
// 开始编码
while(iCount < 256)
{
// 初始化iCount为iStart
iCount = iStart;
// 循环编码
for (i = iStart; i < 256; i ++)
{
// 判断是否编码完成
if (bFinished[i] == FALSE)
{
// 编码没有完成,继续编码
// fSum加当前出现的频率
fSum += fPs[i];
// 判断是否超出总和的一半
if (fSum > fTotal/2.0)
{
// 超出,追加的字符改为0
str = "0";
}
// 编码追加字符1或0
m_strCode[iMap[i]] += str;
// 判断是否编码完一段
if (fSum == fTotal)
{
// 完成一部分编码,重新计算fTotal
// 初始化fSum为0
fSum = 0;
// 判断是否是最后一个元素
if (i == 256 - 1)
{
// 是最后,设置从起始点开始
j = iStart;
}
else
{
// 不是最后,设置从下一个点开始
j = i + 1;
}
// 保存j值
iTemp = j;
str = m_strCode[iMap[j]];
// 计算下一段的fTotal
fTotal = 0;
for (; j < 256; j++)
{
// 判断是否是同一段编码
if ((m_strCode[iMap[j]].Right(1) != str.Right(1))
|| (m_strCode[iMap[j]].GetLength() != str.GetLength()))
break;
// 累加
fTotal += fPs[j];
}
// 初始化str为1
str = "1";
// 判断是否该段长度为1
if (iTemp + 1 == j)
{
// 是,表示该段编码已经完成
bFinished[iTemp] = TRUE;
}
}
}
else
{
// iCount加1
iCount ++;
// 计算下一次循环的fTotal
// 初始化fSum为0
fSum = 0;
// 判断是否是最后一个元素
if (i == 256 - 1)
{
// 是最后,设置从起始点开始
j = iStart;
}
else
{
// 不是最后,设置从下一个点开始
j = i + 1;
}
// 保存j值
iTemp = j;
str = m_strCode[iMap[j]];
// 计算下一段的fTotal
fTotal = 0;
for (; j < 256; j++)
{
// 判断是否是同一段编码
if ((m_strCode[iMap[j]].Right(1) != str.Right(1))
|| (m_strCode[iMap[j]].GetLength() != str.GetLength()))
break;
// 累加
fTotal += fPs[j];
}
// 初始化str为1
str = "1";
// 判断是否该段长度为1
if (iTemp + 1 == j)
{
// 是,表示该段编码已经完成
bFinished[iTemp] = TRUE;
}
}
}
}
//////////////////////////////////////////////////////////
// 对DIB进行编码压缩
// 位掩码
unsigned char Mask[8] = {128, 64, 32, 16, 8, 4, 2, 1};
CString strTemp = "";
// 打开文件
CFile file;
file.Open(strPath, CFile::modeCreate | CFile::modeReadWrite);
// 对各像素进行编码
for (i = 0; i < lHeight; i ++)
{
for (j = 0; j < lLineBytes; j ++)
{
unsigned char V = *((unsigned char *)lpDIBBits + lLineBytes * i + j);
strTemp += m_strCode[V];
int len = strTemp.GetLength();
int loop = 0;
// 保存编码后的数据
do{
unsigned char T = 0;
for (k = 0; k < min(8, strTemp.GetLength()); k++)
{
if (strTemp.Mid(k, 1) == "1")
T |= Mask[k];
}
file.Write(&T, 1);
loop++;
len -= 8;
if (strTemp.GetLength() < 8)
break;
else
strTemp = strTemp.Right(strTemp.GetLength() - 8);
}while (len >= 8);
}
}
// 关闭文件
file.Close();
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 恢复光标
EndWaitCursor();
// 返回TRUE
return TRUE;
}
/*************************************************************************
*
* 函数名称:
* DIBToGIF()
*
* 参数:
* HDIB hDIB - DIB句柄
* CFile& file - 要保存的文件
* BOOL bInterlace - 保存方式
*
* 返回值:
* BOOL - 成功返回True,否则返回False。
*
* 说明:
* 该函数将256色DIB位图保存为GIF文件。
*
*************************************************************************/
BOOL CCoding::DIBToGIF(HDIB hDIB, CFile &file, BOOL bInterlace)
{
// 循环变量
LONG i;
LONG j;
// 锁定DIB
LPBYTE lpDIB = (LPBYTE) ::GlobalLock((HGLOBAL) hDIB);
// 判断是否是8-bpp位图
if (m_clsDIB.DIBBitCount(lpDIB) != 8)
{
// 提示用户
MessageBox("请先将其转换为8位色位图,再进行处理!", "系统提示" , MB_ICONINFORMATION | MB_OK);
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 返回
return FALSE;
}
// GIF文件头
GIFHEADER GIFH;
// GIF逻辑屏幕描述块
GIFSCRDESC GIFS;
// GIF图像描述块
GIFIMAGE GIFI;
// GIF编码参数
GIFC_VAR GIFCVar;
// 调色板
BYTE byGIF_Pal[768];
// 字节变量
BYTE byChar;
// 指向BITMAPINFO结构的指针(Win3.0)
LPBITMAPINFO lpbmi;
// 指向BITMAPCOREINFO结构的指针
LPBITMAPCOREINFO lpbmc;
// 表明是否是Win3.0 DIB的标记
BOOL bWinStyleDIB;
// 更改光标形状
BeginWaitCursor();
// 获取DIB高度
LONG lHeight = m_clsDIB.DIBHeight(lpDIB);
// 获取DIB宽度
LONG lWidth = m_clsDIB.DIBWidth(lpDIB);
// 找到DIB图像象素起始位置
LPBYTE lpDIBBits = m_clsDIB.FindDIBBits(lpDIB);
// 计算每行字节数
LONG lWidthBytes = DWORD_WBYTES(lWidth * 8);
// 给GIFCVar结构赋值
GIFCVar.wWidth = (WORD)lWidth;
GIFCVar.wDepth = (WORD)lHeight;
GIFCVar.wBits = m_clsDIB.DIBBitCount(lpDIB);
GIFCVar.wLineBytes = (WORD)BYTE_WBYTES((DWORD)GIFCVar.wWidth * (DWORD)GIFCVar.wBits);
// 计算颜色数目
LONG lColors = 1 << GIFCVar.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 < lColors; 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 < lColors; 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((LPBYTE)&GIFH, 6);
// 写GIF逻辑屏幕描述块
GIFS.wWidth = GIFCVar.wWidth;
GIFS.wDepth = GIFCVar.wDepth;
GIFS.GlobalFlag.PalBits = GIFCVar.wBits - 1;
GIFS.GlobalFlag.SortFlag = 0x00;
GIFS.GlobalFlag.ColorRes = GIFCVar.wBits - 1;
GIFS.GlobalFlag.GlobalPal = 0x01;
GIFS.byBackground = 0x00;
GIFS.byAspect = 0x00;
file.Write(&GIFS, 7);
// 写GIF全局调色板
file.Write(byGIF_Pal, (lColors * 3));
// 写GIF图像描述间隔符
byChar = 0x2C;
file.Write(&byChar, 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -