⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 coding.cpp

📁 各种数据压缩和解压的源码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
	// 一行一行解码
	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 + -