📄 coding.cpp
字号:
// ************************************************************************
// 文件名:Coding.cpp
//
// 图像编码压缩、解压缩函数库:
//
// LoadJPG() - 装载JPEG图象(解压用)
// SaveJPG() - 保存JPEG图象(压缩用)
// SaveBMP() - 保存BMP图象到文件(解压用)
// LoadBMP() - 从文件装载BMP图象(压缩用)
// DIBToPCX() - 将DIB保存为PCX文件
// PCXToDIB() - 读取PCX文件
// Huffman() - 哈夫曼编码
// Shannon_Fannon() - 仙农-弗诺编码
// DIBToGIF() - 将DIB保存到GIF文件
// LZW_Encode() - 对图象进行LZW编码
// OutputCode() - 为GIF-LZW算法输出一个编码
// GIFToDIB() - 读取GIF到DIB
// LZW_Decode() - 对LZW编码进行解码
// ReadGIF() - 读取指定GIF文件中的图像编码
//
//*************************************************************************
#include "stdafx.h"
#include "Data_Compress_System.h"
#include "Coding.h"
#include "JPEGfile.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// Dib文件头标志(字符串"BM",写DIB时用到该常数)
#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')
/////////////////////////////////////////////////////////////////////////////
// CCoding
CCoding::CCoding()
{
}
CCoding::~CCoding()
{
}
BEGIN_MESSAGE_MAP(CCoding, CWnd)
//{{AFX_MSG_MAP(CCoding)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CCoding message handlers
/*************************************************************************
*
* 函数名称:
* SaveJPG()
*
* 参数:
* CData_Compress_SystemDoc* pDoc - 文档指针
* CString fileName - 保存文件路径
*
* 返回值:
* void - 无返回值
*
* 说明:
* 该函数对图象进行JPEG编码压缩
*
************************************************************************/
void CCoding::SaveJPG(CData_Compress_SystemDoc* pDoc, CString fileName)
{
// 临时缓存
BYTE *buf;
buf = NULL;
//
CSize size = pDoc->GetDocSize();
UINT width = size.cx;
UINT height = size.cy;
buf = LoadBMP(pDoc->m_strCurrentFile, &width, &height);
// 压缩位图到JPEG文件,函数的最后参数标明压缩质量(1 - 100)
JpegFile::RGBToJpegFile(fileName, buf, width, height, TRUE, 80);
}
/*************************************************************************
*
* 函数名称:
* SaveJPG()
*
* 参数:
* CData_Compress_SystemDoc* pDoc - 文档指针
* CString fileName - 保存文件路径
* int quality -质量参数
*
* 返回值:
* void - 无返回值
*
* 说明:
* 该函数对图象进行JPEG编码压缩
*
************************************************************************/
void CCoding::SaveJPG(CData_Compress_SystemDoc* pDoc, CString fileName,int quality)
{
// 临时缓存
BYTE *buf;
buf = NULL;
//
CSize size = pDoc->GetDocSize();
UINT width = size.cx;
UINT height = size.cy;
buf = LoadBMP(pDoc->m_strCurrentFile, &width, &height);
// 压缩位图到JPEG文件,函数的最后参数标明压缩质量(1 - 100)
JpegFile::RGBToJpegFile(fileName, buf, width, height, TRUE, quality);
}
/*************************************************************************
*
* 函数名称:
* SavePC()
*
* 参数:
* HDIB hDIB - DIB句柄
* CString strPath - 要保存的文件路径
*
* 返回值:
* BOOL - 成功返回True,否则返回False。
*
* 说明:
* 该函数将指定的图象保存为PC文件。
*
*************************************************************************/
BOOL CCoding::SavePC(HDIB hDIB, CString strPath)
{
// 循环变量
LONG i;
LONG j;
LONG k;
// 参与预测的象素和当前编码的象素
BYTE bCharA;
BYTE bCharB;
BYTE bCharC;
BYTE bCharD;
// 预测值
BYTE nTemp;
// 预测后的残差
BYTE nDpcm;
// 中间变量
BYTE bChar1;
BYTE bChar2;
// 指向源图像象素的指针
unsigned char* lpSrc;
unsigned char* A;
unsigned char* B;
// 指向编码后图像数据的指针
// BYTE* lpDst;
// 重复像素计数
int iCount;
// 调整顺序:B、G、R
int RGB[3] = {2, 1, 0};
// 打开文件
CFile file;
file.Open(strPath, CFile::modeCreate | CFile::modeReadWrite);
// 缓冲区已使用的字节数
DWORD dwBuffUsed;
// 指向DIB的指针
LPBYTE lpDIB;
// 指向DIB象素指针
LPBYTE lpDIBBits;
// 锁定DIB
lpDIB = (LPBYTE) ::GlobalLock((HGLOBAL) hDIB);
// 找到DIB图像象素起始位置
lpDIBBits = m_clsDIB.FindDIBBits(lpDIB);
// 判断是否是8-bpp位图
if (m_clsDIB.DIBBitCount(lpDIB) != 8)
{
// 提示用户
MessageBox("请先将其转换为8位色位图,再进行处理!", "系统提示" , 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 * 8);
//*************************************************************************
/**********************************************************************
*写入PC文件头信息
***********************************************************************
*/
PCHEADER pcheader;
// 给文件头赋值
pcheader.bManufacturer = 0x0A;
pcheader.bVersion = 5;
pcheader.bEncoding = 1;
// 像素位数(24位色为8位)
pcheader.bBpp = 8;
// 图像相对于屏幕的左上角X坐标(以像素为单位)
pcheader.wLeft = 0;
// 图像相对于屏幕的左上角Y坐标(以像素为单位)
pcheader.wTop = 0;
// 图像相对于屏幕的右下角X坐标(以像素为单位)
pcheader.wRight = lWidth - 1;
// 图像相对于屏幕的右下角Y坐标(以像素为单位)
pcheader.wBottom = lHeight - 1;
// 图像的水平分辨率
pcheader.wXResolution = (WORD)lWidth;
// 图像的垂直分辨率
pcheader.wYResolution = (WORD)lHeight;
// 保留域,设定为0。
pcheader.bReserved = 0;
// 图像色彩平面数目
pcheader.bPlanes = 3;
// 图像的宽度(字节为单位),必须为偶数。
pcheader.wLineBytes = (WORD)lWidth;
// 图像调色板的类型,1表示彩色或者单色图像,2表示图像是灰度图。
pcheader.wPaletteType = 1;
// 制作该图像的屏幕宽度(像素为单位)
pcheader.wSrcWidth = 0;
// 制作该图像的屏幕高度(像素为单位)
pcheader.wSrcDepth = 0;
// 保留域,取值设定为0。
for (i = 0; i < 54; i ++)
{
pcheader.bFiller[i] = 0;
}
// 写入文件头
file.Write((LPBYTE)&pcheader, sizeof(PCHEADER));
//*******************************************************************************
// 开始编码
// 编码第0行
i = 0;
for ( j = 0; j < lWidth; j++)
{
// 指向图象0行j列象素的指针
lpSrc = (BYTE *)lpDIBBits + lLineBytes * (lHeight - 1 - i) +j ;
// 给bCharD赋值
bCharD = (BYTE)*lpSrc;
// 如果是第0行0列,直接将象素值写入
if(j == 0)
{
nDpcm = bCharD;
}
// 利用 Dpcm =D - A 计算残差
else
{
bCharA = *(lpSrc - 1);
nDpcm = bCharD - bCharA;
}
// 将残差写入文件
file.Write(&nDpcm , sizeof(BYTE));
}
// 编码第1行到lHeight-1行
for ( i=1;i<lHeight; i++)
{
for ( j = 0; j < lWidth; j++)
{
// 指向当前编码元素的指针
lpSrc = (BYTE *)lpDIBBits + j + lLineBytes * (lHeight - 1 - i);
// 赋值
bCharD = *lpSrc;
bCharB = *(lpSrc + lLineBytes);
// 如果是第一列,利用 残差=D -B 进行预测
if(j == 0)
nDpcm = bCharD - bCharB;
else
{
// 利用(B-C)/2+A计算预测值
bCharA = *(lpSrc - 1);
bCharC = *(lpSrc + lLineBytes - 1);
nTemp = (BYTE)((bCharB-bCharC) / 2 + bCharA);
// 如果预测值小于0,直接赋零
if(nTemp < 0)
nTemp = 0;
// 如果预测值大于255,直接赋值255
else if(nTemp > 255)
nTemp = 255;
else
nTemp = nTemp;
// 得到残差
nDpcm = bCharD - nTemp;
}
// 将残差写入文件
file.Write(&nDpcm , sizeof(BYTE));
}
}
// 释放内存
//delete[] lpDst;
// 关闭文件
file.Close();
// 更改光标形状
EndWaitCursor();
// 返回
return TRUE;
}
/*************************************************************************
*
* 函数名称:
* LoadJPG()
*
* 参数:
* HDIB hDIB - DIB句柄
* CData_Compress_SystemDoc* pDoc - 文档指针
* CString fileName - 装载文件路径
*
* 返回值:
* void - 无返回值
*
* 说明:
* 该函数对图象进行JPEG编码解压缩
*
************************************************************************/
void CCoding::LoadJPG(HDIB hDIB, CData_Compress_SystemDoc* pDoc, CString fileName)
{
// 临时缓存
BYTE *buf;
buf = NULL;
// JPEG图象高度、宽度
UINT width = 0;
UINT height = 0;
// 读到临时缓存
buf = JpegFile::JpegFileToRGB(fileName, &width, &height);
// 交换红绿象素
JpegFile::BGRFromRGB(buf, width, height);
// 垂直翻转显示
JpegFile::VertFlipBuf(buf, width * 3, height);
// 保存解压后的数据到临时位图文件
SaveBMP("Temp.bmp", buf, width, height);
// 装载临时位图文件
pDoc->OnOpenDocument("Temp.bmp");
// 删除临时文件
::DeleteFile("Temp.bmp");
// 初始化标记为FALSE
pDoc->SetModifiedFlag(TRUE);
}
/*************************************************************************
*
* 函数名称:
* SaveBMP()
*
* 参数:
* CString fileName - 保存文件路径
* BYTE* buf - BGR缓存
* UINT width - 宽度
* UINT height - 高度
*
* 返回值:
* void - 无返回值
*
* 说明:
* 该函数把BMP图象从内存保存到文件
*
************************************************************************/
void CCoding::SaveBMP(CString fileName, BYTE * buf, UINT width, UINT height)
{
// 位图文件头
char m1 = 'B';
char m2 = 'M';
short res1 = 0;
short res2 = 0;
long pixoff = 54;
// 宽度
DWORD widthDW = WIDTHBYTES(width * 24);
// 文件长度
long bmfsize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + widthDW * height;
// 文件指针
long byteswritten = 0;
// 位图信息头
BITMAPINFOHEADER header;
header.biSize = 40; // 头大小
header.biWidth = width;
header.biHeight = height;
header.biPlanes = 1;
header.biBitCount = 24; // 24位
header.biCompression = BI_RGB; // 非压缩
header.biSizeImage = 0;
header.biXPelsPerMeter = 0;
header.biYPelsPerMeter = 0;
header.biClrUsed = 0;
header.biClrImportant = 0;
// 二进制写方式打开文件
FILE *fp;
fp = fopen(fileName, "wb");
// 写文件头
fwrite((BYTE*)&(m1), 1, 1, fp);
byteswritten += 1;
fwrite((BYTE*)&(m2), 1, 1, fp);
byteswritten += 1;
fwrite((long*)&(bmfsize), 4, 1, fp);
byteswritten += 4;
fwrite((int*)&(res1), 2, 1, fp);
byteswritten += 2;
fwrite((int*)&(res2), 2, 1, fp);
byteswritten += 2;
fwrite((long*)&(pixoff), 4, 1, fp);
byteswritten += 4;
// 写位图信息头
fwrite((BITMAPINFOHEADER *)&header, sizeof(BITMAPINFOHEADER), 1, fp);
// 移动指针
byteswritten += sizeof(BITMAPINFOHEADER);
// 临时变量
long row = 0;
long rowidx;
long row_size;
long rc;
// 行大小
row_size = header.biWidth * 3;
// 保存位图阵列
for (row = 0; row < header.biHeight; row++)
{
rowidx = (long unsigned)row * row_size;
// 写一行
rc = fwrite((void *)(buf + rowidx), row_size, 1, fp);
if (rc != 1)
break;
byteswritten += row_size;
for (DWORD count = row_size; count < widthDW; count++)
{
char dummy = 0;
fwrite(&dummy, 1, 1, fp);
byteswritten++;
}
}
// 关闭文件
fclose(fp);
}
/*************************************************************************
*
* 函数名称:
* LoadBMP()
*
* 参数:
* CString fileName - 装载路径
* UINT width - 宽度
* UINT height - 高度
*
* 返回值:
* BYTE* - 读取图象缓存首地址
*
* 说明:
* 该函数把BMP图象从文件装载到内存
*
************************************************************************/
BYTE* CCoding::LoadBMP(CString fileName, UINT *width, UINT *height)
{
BITMAP inBM;
BYTE m1,m2;
long filesize;
short res1,res2;
long pixoff;
long bmisize;
long compression;
unsigned long sizeimage;
long xscale, yscale;
long colors;
long impcol;
// 初始化
BYTE *outBuf = NULL;
*width = 0;
*height = 0;
DWORD m_bytesRead = 0;
// 以二进制读方式打开文件
FILE *fp;
fp = fopen(fileName, "rb");
// 读取文件
if (fp != NULL)
{
// 检验BMP标志
long rc;
rc = fread((BYTE*)&(m1), 1, 1,fp);
m_bytesRead += 1;
if (rc == -1)
{
fclose(fp);
return NULL;
}
rc = fread((BYTE*)&(m2), 1, 1,fp);
m_bytesRead += 1;
if ((m1!='B') || (m2!='M'))
{
fclose(fp);
return NULL;
}
// 读文件头信息
rc = fread((long*)&(filesize), 4, 1, fp);
m_bytesRead += 4;
if (rc != 1)
{
fclose(fp);
return NULL;
}
rc = fread((int*)&(res1), 2, 1, fp);
m_bytesRead += 2;
if (rc != 1)
{
fclose(fp);
return NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -