最近在看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);

这样就可以显示整张位图了。

MFC中显示 .bmp格式的位图的更多相关文章

  1. MFC对话框中显示BMP,JPG图片

    //************************************ // 方法说明:    显示JPG和GIF.BMP图片 // 参数说明:    CDC * pDC           设 ...

  2. MFC对话框显示BMP图片

    1.MFC对话框显示BMP图片我们先从简单的开始吧.先分一个类: (一) 非动态显示图片(即图片先通过资源管理器载入,有一个固定ID) (二) 动态载入图片(即只需要在程序中指定图片的路径即可载入) ...

  3. 火狐低版本中显示时间格式为:yyyy-MM-dd hh:mm:ss,出现NaN

    在低版本的火狐(43以下)和IE8中,显示时间格式为:yyyy-MM-dd hh:mm:ss,会出现NaN:原因是只支持yyyy/MM/dd hh:mm:ss; 所以在new Date('2018-0 ...

  4. MFC中显示一张位图

    1.用类CBitmap加载位图 2.创建内存DC, 将位图选进此内存DC 3.调用BitBlt将内存DC的内容拷贝到其它DC(通知是显示DC) 例子(来自MSDN): // This OnDraw() ...

  5. Linux C语言解析并显示.bmp格式图片

    /************************* *bmp.h文件 *************************/ #ifndef __BMP_H__ #define __BMP_H__ # ...

  6. 在MFC中显示图片(opencv Mat类型)

    1,在MFC窗体中添加picture control控件,并添加对应的变量名 2,在窗体的初始化窗口中添加: namedWindow(); HWND hWnd = (HWND)cvGetWindowH ...

  7. 在RichTextBox控件中显示RTF格式文件

    实现效果: 知识运用:    RichTextBox控件的LoadFile方法 //将文件内容加载到RichTextBox控件中 public void LoadFile(string path,Ri ...

  8. asp:gridview 中显示日期格式

    boundfield中应该这样设置: <asp:BoundField HeaderText="发表时间" DataField="PostTime" Htm ...

  9. 在MFC中显示cmd命令行

    添加函数 void InitConsoleWindow1() { ; FILE* fp; AllocConsole(); nCrt = _open_osfhandle((long)GetStdHand ...

随机推荐

  1. 关于Servlet的PrintWriter 中文乱码问题

    ps:servlet的PrintWriter和ServletOutputStream是不能同时使用的,同时使用会抛异常; PrintWriter是字符流.ServletOutputStream是字节流 ...

  2. IOS-简单计时器的使用

    1. 使用NSTimer *_timer --游戏计时器 2. NSDate *_startTime -- 开始时间 3. 初始化计时器 _timer = [NSTimer scheduledTime ...

  3. xp的虚拟机如何访问本地主机上的文件

    1.选中虚拟机,右键选择Settings,在options选项卡里选择Shared Folders,然后在右边设置要共享的文件夹. 2.power on 虚拟机,然后在虚拟机的VM菜单中,选择“Ins ...

  4. Java多线程的五种状态

    新建状态:new Thread(参数)之后,建立了一个线程对象; 就绪状态:线程对象建立之后,调用start()方法,进入就绪状态,此时并不会直接调用run()方法,线程进入运行状态还需要抢占CPU资 ...

  5. shell 中awk、if while 例子

    1.if while命令写在一行中while read a b;do echo $a $b;done < aa.txt12 13 14cat aa.txt12 13 14if [[ $i -eq ...

  6. WCF寄宿方式

    WCF开发框架形成之旅---WCF的几种寄宿方式 WCF寄宿方式是一种非常灵活的操作,可以在IIS服务.Windows服务.Winform程序.控制台程序中进行寄宿,从而实现WCF服务的运行,为调用者 ...

  7. Linux 的 screen用法

    screen可以将任务挂起,即将任务放在后台,一般5个任务左右. 1.新建screen会话:直接输入screen命令或者screen -S [会话名称] 2.退出会话:按下组合键Ctrl+a并松开,此 ...

  8. Protocol Buffer详解

    1.Protocol Buffer 概念 Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,目前已经正在使用的有超过 48,162 ...

  9. MyEclipse2015对Javascript自动提示的终极支持

    2015通过集成Tern.js,进入了JS自动提示的最新时代 先看看具体效果吧:   点击链接会进入:   而tern.js已经支持相当多的框架:   关键这个提示不只是纯粹的js文件,对于jsp等等 ...

  10. WS之cxf的权限拦截器应用

    一.服务器端: 1.权限判断: package cn.tdtk.ws.interceptor; import java.util.List; import org.apache.cxf.binding ...