📄 bmpcompressdlg.cpp
字号:
str="文件大小->";
::itoa(m_bfsize,strChar1,10);
strcpy(strChar,str);
strcat(strChar,strChar1);
strcat(strChar,"bit");
pDC->TextOut(left+5,top+25,strChar);
if(strTitle=="位图文件名称->")
{
str="颜色位数->";
::itoa(m_numberofcolor,strChar1,10);
strcpy(strChar,str);
strcat(strChar,strChar1);
pDC->TextOut(left+5,top+45,strChar);
}
if(strTitle=="被压缩后文件名称->")
{
str="压缩比->";
strcpy(strChar,str);
strcat(strChar,m_compressionRatio);
pDC->TextOut(left+5,top+45,strChar);
}
}
void CBmpCompressDlg::OnOutofmemoryScaleDisplayBMP(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here
*pResult = 0;
}
void CBmpCompressDlg::OnUpdateClient(int nIDDlgItem)
{
}
void CBmpCompressDlg::OnReleasedcaptureScale(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here
CWnd *pBtn=GetDlgItem(IDDDISPLAY);
CString str;
pBtn->GetWindowText(str);
if((m_Dib.GetData()!=NULL)&&(str!="Display"))
{
m_ratio=((float)m_scale.GetPos())/100;
OnDrawBMP();
*pResult = 0;
}
else
{
MessageBox("没有显示图像!", "系统提示" ,
MB_ICONINFORMATION | MB_OK);
m_scale.SetPos(0);
}
}
BOOL CBmpCompressDlg::CompressBMP(CFile & dibfile)
{
int bH=m_Dib.GetHeight();//the height of BMP
int bW=m_Dib.GetWidth();//the width of BMP
DWORD dwSizeUsedRow=0;//行扫描有用字节数
DWORD dwSizeUsedCol=0;//列扫描有用字节数
DWORD i=0;
BYTE *pBitmapData=m_Dib.GetData();
LPBYTE bufferIn;
LPBYTE bufferOutRow;
LPBYTE bufferOutCol;
DWORD realSize;
realSize=m_Dib.GetSize();
bufferIn=new BYTE[realSize];
bufferIn=pBitmapData;
bufferOutRow=new BYTE[realSize];
bufferOutCol=new BYTE[realSize];
//写入DAT文件头结构
DATHEADER datHdr;
datHdr.bManufacturer= 0x0A;
datHdr.bVersion=5;
datHdr.wHeight=m_Dib.GetHeight();
datHdr.wWidth=m_Dib.GetWidth();
datHdr.numberOfColor=m_numberofcolor;
datHdr.biSizeImage=m_Dib.GetSize();
//压缩编码开始
//选取标志位
int id[255];
memset(id,0,256);//初始化数组
for(i=0;i<realSize;i++)
id[(int)bufferIn[i]]++;
int idOfMinCount=id[0];
BYTE identify;//标志位
for(i=0;i<256;i++)
{ if(id[i]<idOfMinCount)
{
idOfMinCount=id[i];
identify=(BYTE)i;
if(idOfMinCount==0)
break;
}
}
datHdr.identify=identify;
//按行压缩:
BYTE CH=bufferIn[0];
if(CH==identify)
{
if((int)identify!=0)
CH=BYTE((int)identify-1);//如果图像中存在标志位的实际像素将该像素值减一
else
CH=BYTE((int)identify+1);
}
BYTE SC;
int iCount=1;//重复字符个数
for(i=1;i<realSize;i++)
{
SC=bufferIn[i];
if(SC==identify)
{
if((int)identify!=0)
CH=BYTE((int)identify-1);//如果图像中存在标志位的实际像素将该像素值减一
else
CH=BYTE((int)identify+1);
}
if((SC==CH)&&(iCount<255))
iCount++;
else if(iCount<4)
{
memset(&bufferOutRow[dwSizeUsedRow],CH,iCount);
dwSizeUsedRow+=iCount;
iCount=1;
CH=SC;
}
else
{
bufferOutRow[dwSizeUsedRow]=identify;
bufferOutRow[dwSizeUsedRow+1]=iCount;
bufferOutRow[dwSizeUsedRow+2]=CH;
CH=SC;
dwSizeUsedRow+=3;
iCount=1;
}
}
//--保存最后一部分编码
if(iCount<4)
{
memset(&bufferOutRow[dwSizeUsedRow],CH,iCount);
dwSizeUsedRow+=iCount;
CH=SC;
}
else
{
bufferOutRow[dwSizeUsedRow]=identify;
bufferOutRow[dwSizeUsedRow+1]=iCount;
bufferOutRow[dwSizeUsedRow+2]=CH;
CH=SC;
dwSizeUsedRow+=3;
}
//按列压缩:
BYTE **bufferInCol;
bufferInCol=new BYTE *[bH];
for(int index=0;index<bH;index++)
bufferInCol[index]=new BYTE[bW];
int row;
int col;
for(row=0;row<bH;row++)
for( col=0;col<bW;col++)
bufferInCol[row][col]=*bufferIn++;//将像素数据存于二维数组中
CH=bufferInCol[0][0];
if(CH==identify)
{
if((int)identify!=0)
CH=BYTE((int)identify-1);//如果图像中存在标志位的实际像素将该像素值减一
else
CH=BYTE((int)identify+1);
}
iCount=1;//重复字符个数
for( col=0;col<bW;col++)
for( row=0;row<bH;row++)
{
SC=bufferInCol[row][col];
if(SC==identify)
{
if((int)identify!=0)
CH=BYTE((int)identify-1);//如果图像中存在标志位的实际像素将该像素值减一
else
CH=BYTE((int)identify+1);
}
if((SC==CH)&&(iCount<255))
iCount++;
else if(iCount<4)
{
memset(&bufferOutCol[dwSizeUsedCol],CH,iCount);
dwSizeUsedCol+=iCount;
iCount=1;
CH=SC;
}
else
{
bufferOutCol[dwSizeUsedCol]=identify;
bufferOutCol[dwSizeUsedCol+1]=iCount;
bufferOutCol[dwSizeUsedCol+2]=CH;
CH=SC;
dwSizeUsedCol+=3;
iCount=1;
}
}
//----保存最后一部分编码
if(iCount<4)
{
memset(&bufferOutCol[dwSizeUsedCol],CH,iCount);
dwSizeUsedCol+=iCount;
}
else
{
bufferOutCol[dwSizeUsedCol]=identify;
bufferOutCol[dwSizeUsedCol+1]=iCount;
bufferOutCol[dwSizeUsedCol+2]=CH;
dwSizeUsedCol+=3;
}
//计算压缩比,并比较三种扫描方法的压缩比大小取其中最小的。
DWORD dwHdSize=sizeof(DATHEADER)+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)
+sizeof(RGBQUAD)*m_numberofcolor;
m_bfsize=dwHdSize+dwSizeUsedRow;
float ratioRow=((float)m_bfsize/(float)m_Dib.GetFileSize());//按行扫描的压缩比:
m_bfsize=dwHdSize+dwSizeUsedCol;
float ratioCol=((float)m_bfsize/(float)m_Dib.GetFileSize());//按列扫描的压缩比:
float ratio=(ratioRow<ratioCol)?ratioRow:ratioCol;//取小的
::gcvt( ratio*100, 4, m_compressionRatio);//float to string
::strcat(m_compressionRatio,"%");
if(ratio==ratioRow)
datHdr.iWay=0;
else if(ratio==ratioCol)
datHdr.iWay=1;
//写入位图头信息
dibfile.Write((LPSTR)&datHdr,sizeof(DATHEADER));
dibfile.Write((void *)&m_Dib.bitmapFileHeader,sizeof(BITMAPFILEHEADER));
dibfile.Write(m_Dib.m_pBitmapInfoHeader,sizeof(BITMAPINFOHEADER));
dibfile.Write(m_Dib.m_pRGB,sizeof(RGBQUAD)*m_numberofcolor);
//写入最小压缩比的压缩后数据
if(datHdr.iWay==0)
dibfile.WriteHuge((LPSTR)bufferOutRow, dwSizeUsedRow);
else if(datHdr.iWay==1)
dibfile.WriteHuge((LPSTR)bufferOutCol, dwSizeUsedCol);
//显示文件信息
m_filename=dibfile.GetFileName();
m_numberofcolor=-1;
CString str="被压缩后文件名称->";
OnDrawTEXT(str);
//写入压缩后的数据编码文件(十进制)
char strFileName[256];
strcpy(strFileName,dibfile.GetFilePath());
strcat(strFileName,"行扫描");
strcat(strFileName , ".txt");
FILE *fp;
fp=fopen(strFileName,"w");
fprintf(fp,"%s","游程标志=");
fprintf(fp,"%d ",identify);
fprintf(fp,"%s","压缩比=");
fprintf(fp,"%f\n",ratioRow);
fprintf(fp,"%s%d %s%d\n","图像宽度=",bW,"图像高度=",bH);
if(datHdr.iWay==0)
fprintf(fp,"%s\n\n","-->由于压缩比低于列扫描方式,所以被程序采用!");
int irow=0;//换行计数
char c='\n';
for(i=0;i<dwSizeUsedRow;i++)
{
fprintf(fp,"%d ",bufferOutRow[i]);irow++;
if(irow==30)
{
fprintf(fp,"%c",c);irow=0;
}
}
fclose(fp);
strcpy(strFileName,dibfile.GetFilePath());
strcat(strFileName,"列扫描");
strcat(strFileName , ".txt");
fp=fopen(strFileName,"w");
fprintf(fp,"%s","游程标志=");
fprintf(fp,"%d ",identify);
fprintf(fp,"%s","压缩比=");
fprintf(fp,"%f\n",ratioCol);
fprintf(fp,"%s%d %s%d\n","图像宽度=",bW,"图像高度=",bH);
if(datHdr.iWay==1)
fprintf(fp,"%s\n\n","-->由于压缩比低于行扫描方式,所以被程序采用!");
irow=0;//换行计数
for(i=0;i<dwSizeUsedCol;i++)
{
fprintf(fp,"%d ",bufferOutCol[i]);irow++;
if(irow==30)
{
fprintf(fp,"%c",c);irow=0;
}
}
fclose(fp);
return TRUE;
}
BOOL CBmpCompressDlg::DeCompressBmp(CFile & dibfile)
{
//读取DAT文件结构信息
DATHEADER datHdr;
m_CompressFile.Read((LPSTR)&datHdr,sizeof(DATHEADER));
WORD bW= WIDTHBYTES(datHdr.wWidth * 8);
WORD bH=datHdr.wHeight;
WORD numOfColor=datHdr.numberOfColor;
DWORD realSize=datHdr.biSizeImage;
BYTE identify=datHdr.identify;
//处理位图文件结构头,信息头,颜色表
LPBYTE buffer;
buffer=new BYTE[sizeof(BITMAPFILEHEADER)];
m_CompressFile.Read(buffer,sizeof(BITMAPFILEHEADER));
dibfile.Write(buffer,sizeof(BITMAPFILEHEADER));
buffer=new BYTE[sizeof(BITMAPINFOHEADER)];
m_CompressFile.Read(buffer,sizeof(BITMAPINFOHEADER));
dibfile.Write(buffer,sizeof(BITMAPINFOHEADER));
buffer=new BYTE[sizeof(RGBQUAD)*numOfColor];
m_CompressFile.Read(buffer,sizeof(RGBQUAD)*numOfColor);
dibfile.Write(buffer,sizeof(RGBQUAD)*numOfColor);
//解压缩位图(像素)数据
LPBYTE bufferIn;
LPBYTE bufferOut;
DWORD i=0;
DWORD size=0;//bufferOut的下标
int iCount=0;//重复字符个数
BYTE bChar;
DWORD sizeData=0;
sizeData=m_CompressFile.GetLength()-sizeof(DATHEADER)-
sizeof(BITMAPFILEHEADER)-sizeof(BITMAPINFOHEADER)
-sizeof(RGBQUAD)*numOfColor;
bufferIn=new BYTE[sizeData];
m_CompressFile.Read(bufferIn,sizeData);
bufferOut=new BYTE[bW*bH*2];
for(i=0;i<sizeData;i++)
{
bChar=bufferIn[i];
if(bChar==identify)
{
bChar=bufferIn[i+1];
iCount=(int)bChar;
bChar=bufferIn[i+2];
i+=2;
memset(bufferOut,bChar,iCount);
bufferOut+=iCount;
size+=iCount;
}
else
{
*bufferOut=bChar;
bufferOut+=1;
size+=1;
}
}
bufferOut-=size;
if(datHdr.iWay==0) //行扫描的解压存储
{
dibfile.WriteHuge((LPSTR)bufferOut,size);
delete[] bufferOut;
}
else if(datHdr.iWay==1) //列扫描的解压
{
BYTE **bufferOutCol=new BYTE *[bH];
for(int index=0;index<bH;index++)
bufferOutCol[index]=new BYTE[bW];
int row=0;
int col=0;
BYTE bcharX='0';
DWORD dwSz=0;
for(col=0;col<bW;col++)
for(row=0;row<bH;row++)
{
bcharX=bufferOut[dwSz];
bufferOutCol[row][col]=bcharX;
dwSz++;
}
LPBYTE bufferResultCol;
bufferResultCol=new BYTE[dwSz];
for(row=0;row<bH;row++)
for(col=0;col<bW;col++)
{
bcharX=bufferOutCol[row][col];
*bufferResultCol=bcharX;
bufferResultCol++;
}
bufferResultCol-=dwSz;
dibfile.WriteHuge((LPSTR)bufferResultCol,dwSz);
delete[] bufferResultCol;
}
CString str="解压缩后文件名称->";
m_bfsize=dibfile.GetLength();
OnDrawTEXT(str);
m_CompressFile.SetFilePath("");
dibfile.Close();
return TRUE;
}
void CBmpCompressDlg::OnDisplay() //显示位图
{
// TODO: Add your control notification handler code here
//图象显示比例
CWnd *pBtn=GetDlgItem(IDDDISPLAY);
CString str;
pBtn->GetWindowText(str);
if(m_Dib.GetData()!=NULL)
{
if(str=="Display")
{
pBtn->SetWindowText("HidePicture");
m_ratio=1.0;
m_scale.SetPos((int)(m_ratio*100));
OnDrawBMP();
}
else
{
OnHideBMP();
m_scale.SetPos(0);
}
}
else
{
AfxMessageBox("请先装载位图文件!");
return ;
}
}
void CBmpCompressDlg::OnHideBMP()
{
//刷新显示区
CRect rect;
CWnd *pDisplay=GetDlgItem(IDC_BMPINFO);
pDisplay->GetWindowRect(rect);
ScreenToClient(rect);
CDC * pDC=GetDC();
CBrush brush(RGB(255,255,255));
rect.SetRect(rect.left+5,rect.top+5,rect.right-5,rect.bottom-5);
pDC->FillRect(&rect,&brush);
CWnd *pBtn=GetDlgItem(IDDDISPLAY);
CString str;
pBtn->GetWindowText(str);
pBtn->SetWindowText("Display");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -