MFC中显示.bmp格式的位图
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
MFC中显⽰.bmp格式的位图
最近在看VisualC++ 图像处理的书籍,表⽰⼀直在从基础做起,今天就记录⼀个简单功能的实现,显⽰.bmp格式的位图。
⾸先需要理解的是窗⼝创建的过程包括两个步骤:⾸先擦除窗⼝的背景,然后在对窗⼝进⾏重新绘制。
⼀般⽽⾔,对于单⽂档或多⽂档的MFC程序,显⽰图像的代码要放在OnDraw函数之中。
刚刚说过,窗⼝重绘时,要先将窗⼝的背景擦除,也就是发送WM_ERASEBKGND消息,然后⽤OnEraseBkgnd()函数处理这个消息,所以我们的显⽰图像的代码也可以放在这个函数之中。
当然,这⾥只是为了实现显⽰位图这⼀个功能,在实际⼯程中,要根据实际情况,选择代码放置的地⽅。
下⾯先给出代码,然后⼀⾏⼀⾏地详细解释:
BOOL CLoadBitmapView::OnEraseBkgnd(CDC* pDC)
{
// TODO: 在此添加消息处理程序代码和/或调⽤默认值
//return FALSE;
HBITMAP hBit;
hBit=(HBITMAP) LoadImage(NULL,_T("D:\\Axing.bmp"),IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION); //载⼊图像
CBitmap cBit;
cBit.Attach(hBit);
CDC MemDC;
MemDC.CreateCompatibleDC(pDC); //创建与当前设备描述表相适应的内存DC
BITMAP bitmap;
cBit.GetBitmap(&bitmap);
CBitmap *oldBit;
oldBit=MemDC.SelectObject(&cBit);
CRect rect;
GetClientRect(&rect);
pDC->BitBlt(100,100,rect.Width()/2.5,rect.Height(),&MemDC,0,0,SRCCOPY);
return TRUE;
//return CView::OnEraseBkgnd(pDC);
}
⾸先来解释⼀下HBITMAP、CBitmap、BITMAP三者之间的关系。
HBITMAP是图⽚的句柄,CBitmap是MFC定义的⼀个类,在这个类中对HBITMAP进⾏了封装,BITMAP则是⼀个结构体,这个结构体中保存着位图的各种信息(如宽度和⾼度等)。
有三个函数是和这三个类型息息相关的。
第⼀个:Attach(),这个函数是CBitmap类的成员函数,作⽤就是将HBITMAP类型转换成CBitmap类型。
我们在代码中会⽤到它。
第⼆个:GetBitmap(),这个函数也是CBitmap类的成员函数,作⽤就是获取位图的信息,并将位图的信息保存在BITMAP 结构指针中。
第三个:GetObject(),这个函数的作⽤就是,从HBITMAP句柄中获取BITMAP结构。
这三个函数的具体⽤法,详细说明在这⾥就不赘述了,⽤的时候可以百度⼀下很⽅便的。
我们先建⽴了⼀个HBITMAP类型的句柄,然后⽤LoadImage()函数来载⼊⼀个位图,并保存位图的句柄。
之后,创建⼀个CBitmap类的对象,然后将HBITMAP转换成CBitmap对象(⽤Attach()函数)。
之后⽤CReateCompatibleDC()函数,创建⼀个与当前设备上下⽂相兼容的内存DC。
问题来了,为什么要创建这个内存DC呢?
其实,这个内存DC的作⽤就是缓冲。
如果需要对屏幕进⾏⽐较多的GUI操作,如果直接对屏幕DC进⾏操作,会导致同显⽰内存之间的过于频繁的数据交换,于是程序运⾏效率将受到严重影响。
任何绘图的过程都是这样,要完成⼀幅图像的显⽰,总是在显⽰终端上依次绘制每个像素点,以形成完整的图像。
我们在内存中虚拟⼀块画布(就是内存DC),绘图时仅仅对内存进⾏操作。
待政府图像绘制完成时在整
体复制到屏幕上,这样避免了外设和内存之间频繁的数据交换,程序的运⾏效率会提⾼很多。
这就是使⽤CreateCompatibleDC()函数创建内存DC 的作⽤。
接着,我们将位图选⼊到内存DC中(MemDC.SelectObject(&cBit)),这⼀步也是相当重要的。
因为当兼容的内存DC创建的时候,他的显⽰表⾯是标准的⼀个单⾊像素宽和单⾊像素⾼。
在应⽤程可以使⽤内存DC进⾏绘图操作之前,必须将⼀个具有正确⾼度和宽度的位图,选⼊到内存DC中,这时内存设备上下⽂显⽰表⾯的⼤⼩就由当前选⼊的位图决定了。
之后CRect rect;GetClientRect(&rect);⽤于获取客户区。
最后⽤BitBlt()函数将内存DC中的内容复制到当前DC中,显⽰位图完毕。
这⾥要解释⼀下BitBlt函数,它的函数原型为:
BOOLBitBlt(int x,int y,int nWidth,int nHeight,CDC*pSrcDC,int xSrc,int ySrc,DWORDdwRop);
参数x、y表⽰⽬的DC(当前设备上下⽂)矩形区域的左上⾓坐标,nWidth,nHeight,表⽰矩形区域的宽和⾼,pSRCDC则是源DC(内存DC)的指针,xSrc和ySrc表⽰源DC矩形区域的左上⾓坐标。
我们可以看到并没有参数表⽰源⽬的矩形区域的宽和⾼,这样,区域之间的复制只能是1:1的,所以当图像⽐较⼤时,只能显⽰图像的⼀部分。
为了解决这个问题,可以⽤StretchBlt()函数,这个函数和BitBlt()函数的功能基本⼀致,只是可以对图像进⾏伸缩变换,这是因为在StretchBlt()函数中增加了两个参数,表⽰源DC矩形区域的⼤⼩。
所以上⾯的代码可以改成
pDC->StretchBlt(100,100,rect.Width()/2.5,rect.Height(),&MemDC,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);。
这样就可以显⽰整张位图了。