读取bmp文件,缩放后保存

思路:先把bmp文件读取到内存,在内存根据客户区大小进行缩放,显示在客户区,然后读取客户区图像,写bmp文件。

需要注意的是,bmp有自己的文件结构,读写的时候按结构读写。

位图文件可看成由4个部分组成:位图文件头(bitmap-file header)、位图信息头(bitmap-information header)、彩色表(color table)和定义位图的字节阵列。

位图文件头主要标示文件大小,文件从开始到像素阵列的偏移值;位图信息表包括位图阵列的宽、高、每个像素占的位数等、彩色表不一定有,如果像素是1位的话,只有黑白两种颜色,没有位图表,8位的时候有256种颜色,这时就有彩色表,彩色表每个颜色值是一个4字节的RGBQUAD结构。RGBQUAD中red green blue 和alpha通道值个占一个字节;位图字节阵列则是位图的像素值。

实现的代码如下

void CTransSizeDlg::OnButtonTrans(CString m_bmpPathname,CString m_newbmppathname

// m_bmpPathname 源文件路径

//m_newbmppathname 保存新文件的全路径
{
// TODO: Add your control notification handler code here
CClientDC dc(this);
    CRect rect;
GetClientRect(&rect);
unsigned char *pBmpBuf;//读入图像数据的指针
int bmpWidth=rect.Width();//图像的宽
int bmpHeight=rect.Height();//图像的高
RGBQUAD *pColorTable;//颜色表指针
    int biBitCount;//图像类型,8位时有颜色表
int bytePerPix; //每像素宽度,即每像素占字节数
int bmpFileSize; //存储缩放后的文件大小
    int linewide;


    //读取bmp原图
FILE *fp=fopen(m_bmpPathname,"rb");
if(fp==0) return ;
BITMAPFILEHEADER fileHead;     //存放文件头第一部分,包含文件大小等信息
BITMAPINFOHEADER head;         //文件头第二部分,包括位图宽,高,像素大小等信息
fread(&fileHead,sizeof(BITMAPFILEHEADER),1,fp);    //读取文件头
fread(&head,sizeof(BITMAPINFOHEADER),1,fp);      //读取第二部分头
    head.biHeight=bmpHeight;
head.biWidth=bmpWidth;
biBitCount=head.biBitCount;
bytePerPix=biBitCount/8;
linewide = (int)(head.biWidth*head.biBitCount+31)/32*4;
if(biBitCount==8)
  bmpFileSize=bmpHeight*bmpWidth*bytePerPix+54+1024;
else
       bmpFileSize=bmpHeight*bmpWidth*bytePerPix+54;
fileHead.bfSize=bmpFileSize;


if(biBitCount==8)
{
  pColorTable=new RGBQUAD[256];
  fread(pColorTable,sizeof(RGBQUAD),256,fp);
}  
    fclose(fp);


CFile cfile;
cfile.Open(m_bmpPathname,CFile::modeRead);
int filesize=cfile.GetLength();
BYTE *buf=new BYTE[filesize];
cfile.Read(buf,filesize);
cfile.Close();
    //位图读入内存
    HBITMAP bmp;
BITMAPFILEHEADER *pbmfh;
pbmfh=(BITMAPFILEHEADER *)buf;
bmp=CreateDIBitmap(dc,
(BITMAPINFOHEADER *) (pbmfh + 1),
CBM_INIT,
(BYTE *) pbmfh + pbmfh->bfOffBits,
(BITMAPINFO *) (pbmfh + 1),
DIB_RGB_COLORS);
BITMAPINFOHEADER *pbminfohead=(BITMAPINFOHEADER *) (pbmfh + 1);
CDC *pDC=GetDC();
CDC bmpDC;
    bmpDC.CreateCompatibleDC(pDC);
    bmpDC.SelectObject(bmp);
//设定缩放模式
    pDC->SetStretchBltMode(HALFTONE);
pDC->StretchBlt(0,0,bmpWidth,bmpHeight,&bmpDC,0,0,pbminfohead->biWidth,pbminfohead->biHeight,SRCCOPY);


//读取客户区上显示的放大后的位图
CDC dstDC;
CBitmap detbmp;
dstDC.CreateCompatibleDC(pDC);
detbmp.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());
CBitmap *oldBmp;
oldBmp=dstDC.SelectObject(&detbmp);
dstDC.BitBlt(0,0,rect.Width(),rect.Height(),pDC,0,0,SRCCOPY);
dstDC.SelectObject(oldBmp);


    BYTE *pBits=new BYTE[linewide*head.biHeight];
HDC hdc;
hdc=::GetDC(NULL);
GetDIBits(hdc,(HBITMAP)detbmp.GetSafeHandle(),0,bmpHeight,pBits,(BITMAPINFO *)  &head,DIB_RGB_COLORS);
    //写新的位图进文件
CFile filesaveas;
filesaveas.Open(m_newbmppathname,CFile::modeCreate|CFile::modeWrite);
filesaveas.Write(&fileHead,sizeof(BITMAPFILEHEADER));
filesaveas.Write(&head,sizeof(BITMAPINFOHEADER));
if(biBitCount==8)
filesaveas.Write(&pColorTable,sizeof(RGBQUAD)*256);
filesaveas.Write(pBits,linewide*head.biHeight);
filesaveas.Close();


if(biBitCount==8)
delete pColorTable;  
delete pBits;
    delete buf;

}

你可能感兴趣的:(vc++)