📄 coding.cpp
字号:
// 一行一行解码
for (j = 0; j < lHeight; j++)
{
for (k = 0; k < 3; k++)
{
i = 0;
while (i < lWidth)
{
// 读取一个字节
bChar = *lpTemp;
lpTemp++;
if ((bChar & 0xC0) == 0xC0)
{
// 行程
iCount = bChar & 0x3F;
// 读取下一个字节
bChar = *lpTemp;
lpTemp++;
// bChar重复iCount次保存
for (l = 0; l < iCount; l++)
*(lpDst + (lHeight - j - 1) * lLineBytes + (i + l) * 3 + RGB[k]) = bChar;
// 已经读取像素的个数加iCount
i += iCount;
}
else
{
// 保存当前字节
*(lpDst + (lHeight - j - 1) * lLineBytes + i * 3 + RGB[k]) = bChar;
// 已经读取像素的个数加1
i += 1;
}
}
}
}
// 释放内存
delete lpSrc;
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 关闭文件
file.Close();
// 返回DIB句柄
return hDIB;
}
HDIB CCoding::PCToDIB(CString strPath)
{
// PCX文件头
PCHEADER pcheader;
// DIB大小(字节数)
DWORD dwDIBSize;
// DIB句柄
HDIB hDIB;
// DIB指针
LPBYTE pDIB;
// 循环变量
LONG i;
LONG j;
LONG k;
LONG l;
// 参与预测的象素和当前编码的象素
BYTE bCharA;
BYTE bCharB;
BYTE bCharC;
BYTE bCharD;
// 重复像素计数
int iCount;
// 调整RGB顺序
int RGB[3] = {2, 1, 0};
// 中间变量
BYTE bChar;
// 指向源图像象素的指针
BYTE * lpSrc;
// 指向编码后图像数据的指针
BYTE * lpDst;
// 临时指针
BYTE * lpTemp;
// 打开文件
CFile file;
file.Open(strPath, CFile::modeReadWrite);
// 尝试读取PCX文件头
if (file.Read((LPBYTE)&pcheader, sizeof(pcheader)) != sizeof(pcheader))
{
// 大小不对,返回NULL。
return NULL;
}
// 判断是否是24位色PCX文件,检查第一个字节是否是0x0A,
if ((pcheader.bManufacturer != 0x0A) || (pcheader.bBpp != 8) || (pcheader.bPlanes != 3))
{
// 非24位色PCX文件,返回NULL。
return NULL;
}
// 获取图像高度
LONG lHeight = pcheader.wBottom - pcheader.wTop + 1;
// 获取图像宽度
LONG lWidth = pcheader.wRight - pcheader.wLeft + 1;
// 计算图像每行的字节数
LONG lLineBytes = WIDTHBYTES(lWidth * 24);
// 计算DIB长度(字节)
dwDIBSize = sizeof(BITMAPINFOHEADER) + 1024 + lHeight * lLineBytes;
// 为DIB分配内存
hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwDIBSize);
if (hDIB == 0)
{
// 内存分配失败,返回NULL。
return NULL;
}
// 锁定
pDIB = (LPBYTE) ::GlobalLock((HGLOBAL) hDIB);
// 指向BITMAPINFOHEADER的指针
LPBITMAPINFOHEADER lpBI;
// 赋值
lpBI = (LPBITMAPINFOHEADER) pDIB;
// 给lpBI成员赋值
lpBI->biSize = 40;
lpBI->biWidth = lWidth;
lpBI->biHeight = lHeight;
lpBI->biPlanes = 1;
lpBI->biBitCount = 24;
lpBI->biCompression = BI_RGB;
lpBI->biSizeImage = lHeight * lLineBytes;
lpBI->biXPelsPerMeter = pcheader.wXResolution;
lpBI->biYPelsPerMeter = pcheader.wYResolution;
lpBI->biClrUsed = 0;
lpBI->biClrImportant = 0;
// 分配内存以读取编码后的象素
lpSrc = new BYTE[file.GetLength() - sizeof(PCHEADER) ];
lpTemp = lpSrc;
// 读取编码后的象素
if (file.ReadHuge(lpSrc, file.GetLength() - sizeof(PCHEADER)) !=
file.GetLength() - sizeof(PCHEADER) )
{
// 大小不对。
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 释放内存
::GlobalFree((HGLOBAL) hDIB);
// 返回NULL。
return NULL;
}
// 计算DIB中像素位置
lpDst = (BYTE *) m_clsDIB.FindDIBBits(pDIB);
BYTE nTemp;
// BYTE * lpTemp1 =lpDst;
// BYTE X,A,B;
//lpDst=lpDst+file.GetLength()-sizeof(PCHEADER);
/* lptemp=lptemp1;
for(i=lHeight-1;i>0;i--)
for(j=lWidth-1;j>0;j--)
{
lpTemp=(BYTE *)lpTemp + lLineBytes * i +j;
lpTemp1=(BYTE *)lpTemp1 + lLineBytes * i +j;
if(i==lHeight-1&&j==lWidth-1)
{
*lpTemp1=*lpTemp;
}
else
{
x=lpTemp;
*(lpTemp-1)=2*x-*(lptemp-lLineBytes)
}
}
*/
/* i=0;
for ( i=0;i<lHeight; i++)
for ( j = 0; j < lWidth; j++)
{
// 给bCharD赋值
bCharD = (BYTE)*lpTemp++;
// 如果是第0行0列,直接将象素值写入
if(j == 0)
{
*lpDst++ = bCharD;
}
// 利用 Dpcm =D - A 计算残差
else
{
char bCharA = *(lpTemp - 1);
*lpDst ++= bCharD + bCharA;
}
lpTemp++;
}
*/
/*
for ( i=0;i<lHeight; i++)
{
for ( j = 0; j<lWidth; j++)
{
bCharD = *lpTemp;
bCharB = *(lpTemp + lLineBytes);
if(j==0)
{
*lpDst++=bCharD+bCharB;
}
else
{
bCharA = *(lpTemp - 1);
bCharC = *(lpTemp + lLineBytes - 1);
BYTE nTemp = ((BYTE)(bCharB-bCharC) / 2 + bCharA);
// 如果预测值小于0,直接赋零
if(nTemp < 0)
nTemp = 0;
// 如果预测值大于255,直接赋值255
else if(nTemp > 255)
nTemp = 255;
else
nTemp = nTemp;
// 得到残差
*lpDst++ = bCharD + nTemp;
}
}
}
*/
// 解码第0行
i = 0;
for(j = 0; j < lWidth; j++)
{
if(j==0)
{
// 如果是0行0列,编码值就是真实值
lpDst[j + lLineBytes * (lHeight - 1 - i)] = (BYTE)(*lpTemp);
lpTemp ++;
}
else
{
// 利用 D=A+残差 得到原来的象素
lpDst[j+ lLineBytes * (lHeight - 1 - i)]
= (BYTE)(*lpTemp) + lpDst[j + lLineBytes * (lHeight - 1 - i) - 1];
lpTemp++;
}
}
// 解码第1行到第lHeight-1行
for (i = 1; i < lHeight; i++)
{
for (j = 0; j < lWidth; j++)
{
// 得到象素B的值
bCharB = lpDst[j + lLineBytes * (lHeight - i)];
// 解码第一列
if(j==0)
{
// 利用 D=B+残差 得到原来的象素值
lpDst[j+ lLineBytes * (lHeight - 1 - i)] = (BYTE)((*lpTemp) + bCharB);
lpTemp++;
}
// 解码剩下的列
else
{
// 利用 D=(B-C)/2 + A + 残差 得到原来的象素值
bCharA=lpDst[j - 1 + lLineBytes * (lHeight - 1 - i)];
bCharC=lpDst[j - 1 + lLineBytes * (lHeight - i)];
// 解码时的预测
nTemp=(BYTE)((bCharB - bCharC) / 2 +bCharA);
// 预测值小于0,直接赋0
if(nTemp<0)
nTemp = 0;
// 预测值大于255,直接赋值255
else if(nTemp>255)
nTemp = 255;
else
nTemp = nTemp;
// 预测值+残差
lpDst[j + lLineBytes * (lHeight - 1 - i)]
= (BYTE)(*lpTemp + (BYTE)nTemp);
lpTemp++;
}
}
}
// 释放内存
delete lpSrc;
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 关闭文件
file.Close();
// 返回DIB句柄
return hDIB;
}
/*************************************************************************
*
* 函数名称:
* Huffman()
*
* 参数:
* HDIB hDIB - 待编码DIB句柄
* CString strPath - 要装载的文件路径
*
* 返回值:
* BOOL - 成功返回True,否则返回False。
*
* 说明:
* 该函数对指定DIB位图进行编码
*
*************************************************************************/
BOOL CCoding::Huffman(HDIB hDIB, CString strPath)
{
// 循环变量
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;
//////////////////////////////////////////////////////////
// 用冒泡法对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;
// 更新映射关系
for (k = 0; k < 256; k ++)
{
// 判断是否是fPs[i]的子节点
if (iMap[k] == i)
{
// 映射到节点i+1
iMap[k] = i + 1;
}
else if (iMap[k] == i + 1)
{
// 映射到节点i
iMap[k] = i;
}
}
}
}
}
//////////////////////////////////////////////////////////
// 计算哈夫曼编码表
for (i = 0; i < 256 - 1; i ++)
{
// 寻找第一个不为0的概率灰度级
if (fPs[i] > 0)
break;
}
// 开始编码
for (i = i; i < 256 - 1; i ++)
{
// 更新m_strCode
for (k = 0; k < 256; k ++)
{
// 判断是否是fPs[i]的子节点并编码字符串
if (iMap[k] == i)
m_strCode[k] = "1" + m_strCode[k];
else if (iMap[k] == i + 1)
m_strCode[k] = "0" + m_strCode[k];
}
// 概率最小的两个概率相加,结果保存到fPs[i + 1]
fPs[i + 1] += fPs[i];
// 改变映射关系
for (k = 0; k < 256; k ++)
{
// 判断是否是fPs[i]的子节点
if (iMap[k] == i)
{
// 映射到节点i+1
iMap[k] = i + 1;
}
}
// 重新排序
for (j = i + 1; j < 256 - 1; j ++)
{
if (fPs[j] > fPs[j + 1])
{
// 互换
float fTemp = fPs[j];
fPs[j] = fPs[j + 1];
fPs[j + 1] = fTemp;
// 更新映射关系
for (k = 0; k < 256; k ++)
{
// 判断是否是fPs[i]的子节点
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);
}
}
// LPCTSTR p=strTemp;
// file.Write((LPBYTE)p,sizeof(p));
// 关闭文件
file.Close();
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 恢复光标
EndWaitCursor();
// 返回TRUE
return TRUE;
}
/*************************************************************************
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -