OK,在上一篇文章中我提到了VC6和VS的差别,在VC6中我们只能依赖于CBITMAP HBITMAP以及BITMAP之间的转化关系,而在VS中,我们用CIMAGE类就可以全部搞定,那么究竟这三个类之间的转化关系是什么样的呢?图像显示的时候该怎么使用呢,别着急,听我慢慢道来。

一、区分概念:首先:

BITMAP是C++中定义的位图结构体

HBITMAP是Windows中使用的位图句柄

CBitmap是MFC封装的位图类

HBITMAP是bitmap的指针,

msdn中如是:Handle to a bitmap.typedef HANDLE HBITMAP;

CBitmap是mfc中封装bitmap的类;

msdn中:Encapsulates(囊括) a Windows graphics device interface (GDI) bitmap and provides member functions to manipulate(操作) the bitmap.

BITMAP是一个结构体,封装着bitmap的一些信息。定义了逻辑位图的高,宽,颜色格式和位值。

MSDN中如是:This structure defines the type, width, height, color format, and bit values of a bitmap.

HBITMAP的全称是Handle BITMAP,也就是说HBITMAP实际上是一个句柄,如果想要活的位图的长,宽之类的参量,只能从BITMAP下手,因为只有BITMAP中才有这些成员函数。

二:相互转换(这部分内容是转载整理的)

1、HBITMAP->CBitmap

方法一:

HBITMAP hBitmap=(HBITMAP)::LoadImage(NULL, str, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
CBitmap bitmap;
bitmap.Attach(hBitmap);
方法二:

HBITMAP hBitmap = (HBITMAP)::LoadImage(NULL, str, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);        
CBitmap *bitmap=CBitmap::FromHandle(hBitmap);

注意:Attach和FromHandle的区别

FromHandle得到的指针是临时变量,通过Attach连接的句柄可以长久保留,但通过FromHandle得到的只是暂时的,大概只在一个消息区间内有效,很快便会被删除,所以基本上不能用。我用了FromHandle然后一直出错!!!

实验源码,在(OnPaint函数中添加)

CString str = _T("E:\\picture\\lena.bmp");
HBITMAP hBitmap=(HBITMAP)::LoadImage(NULL, str, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
CBitmap bitmap;
bitmap.Attach(hBitmap);
CPaintDC dc(this);
CDC MemDC;
MemDC.CreateCompatibleDC(&dc);
MemDC.SelectObject(&bitmap);
CRect rect;
GetClientRect(&rect);
dc.BitBlt(0, 0, rect.Width(), rect.Height(), &MemDC, 0, 0, SRCCOPY);

注意:CBitmap类中的成员函数:

BOOL LoadBitmap(LPCTSTR lpszRecourceName);   
BOOL LoadBitmap(UINT nIDResource);

都可以加载位图,但他们只能加载工程中的位图,不能像LoadImage一样,加载硬盘中的位图。尤其要注意:

BOOL LoadBitmap(LPCTSTR lpszRecourceName)函数中的lpszRecourceName不能为路径字符串。它指的是位图的ID是用字符串表示的。

比如:我在工程中创建了一个位图资源IDB_BITMAP1 ,lpszResourceName是指什么呢,是硬盘上的bitmap1.bmp吗,如果是,以下代码为什么是错的。

CBitmap   bmp;   
bmp.LoadBitmap("d:\\..\\res\\bitmpa1.bmp");   
CDC   memdc;   
BITMAP   bm;   
bmp.GetBitmap(&bm);   
memdc.CreateCompatibleDC(pDC);   
memdc.SelectObject(&bmp);   
pDC->BitBlt(0,0,bm.bmWidth,bm.bmHeight,&memdc,0,0,SRCCOPY);

用Notepad打开*.rc文件,找到类似下面一行:

IDB_BITMAP   BITMAP   "res\\background.bmp"   
改成:Bitmap1   BITMAP   "res\background.bmp"   
或者,在VC中察看位图资源的属性,将其ID栏内改为"Bitmap"(注意,一定要加引号)。
然后调用:bmp.LoadBitmap("Bitmap1"); 保证成功。   
资源可以用一个整数来标示,也可以用一个字符串标示。但无论如何,这些ID都不是指位图文件名。

2、HBITMAP->BITMAP

CString str = _T("E:\\picture\\lena.bmp");
HBITMAP hBitmap = (HBITMAP)::LoadImage(NULL, str, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
BITMAP bm;
::GetObject(hBitmap, sizeof(bm), &bm);
3、CBitmap->BITMAP

CBitmap bitmap;
bitmap.LoadBitmapW(IDB_BITMAP1);
BITMAP bm;
bitmap.GetBitmap(&bm);
4、CBitmap->HBITMAP

方法一:

CBitmap bitmap;        
bitmap.LoadBitmapW(IDB_BITMAP1);
HBITMAP hBitmap = (HBITMAP)bitmap.m_hObject;
方法二:

CBitmap bitmap;
bitmap.LoadBitmapW(IDB_BITMAP1);
HBITMAP hBitmap = (HBITMAP)bitmap;
5、BITMAP->HBITMAP

HBITMAP hBitmap;

pbm->GetHBITMAP(NULL, &hBitmap);
6、BITMAP->CBitmap

Bitmap* pBitmap = new Bitmap(width,height,PixelFormat24bppRGB);
HBITMAP hBitmap;
BITMAP bm;
pBitmap ->GetHBITMAP(NULL,&hBitmap);
CBitmap* bmp;
bmp.Attach(hBitmap);

三、CBITMAP能加载的是在资源位图中的变量,而HBITMAP可以加载路径中的变量,这是两者的区别,下面说一下在画图的时候的区别:

(1)在VS中加载图片用CIMAGE就足够了,这里主要实现的功能是将图片显示到picture控件中,如果图片小于picture控件,那么按照原图显示,否则的话,等比例缩小(为了保证图片不变形)

CString strFilePath;
TCHAR szFilter[]=_T("图片(*.bmp)|*.bmp");
CFileDialog fileDlg(TRUE,_T("picture"),NULL,0,szFilter,this);
if(IDOK==fileDlg.DoModal())
{
strFilePath=fileDlg.GetPathName();
strFilePath.Replace(_T("\\"),_T("\\\\"));
    }
int height, width;
    CRect rect;//定义矩形类
    CRect rect1;
    CImage image; //创建图片类
//image.Load(imgPath);
//image.Load(_T("D:\\test1.bmp"));  
    image.Load(strFilePath);  
    height = image.GetHeight();
    width = image.GetWidth();

//m_PictureControl.GetClientRect(&rect); //获得pictrue控件所在的矩形区域
    GetDlgItem(IDC_SHOWPIC_STATIC)->GetClientRect(&rect);  
    CDC *pDc = m_jzmPicture.GetDC();//获得pictrue控件的Dc
    SetStretchBltMode(pDc->m_hDC,STRETCH_HALFTONE);

if(width<=rect.Width() && height<=rect.Width()) //小图片,不缩放
    {
     rect1 = CRect(rect.TopLeft(), CSize(width,height));
     image.StretchBlt(pDc->m_hDC,rect1,SRCCOPY); //将图片画到Picture控件表示的矩形区域
    return ;
    }
    else
    {
    float xScale=(float)rect.Width()/(float)width;
    float yScale=(float)rect.Height()/(float)height;
//float ScaleIndex=(xScale>=yScale:xScale,yScale);
   float ScaleIndex=(xScale<=yScale)?xScale:yScale;
    rect1 = CRect(rect.TopLeft(), CSize((int)width*ScaleIndex,(int)height*ScaleIndex));
   image.StretchBlt(pDc->m_hDC,rect1,SRCCOPY); //将图片画到Picture控件表示的矩形区域
    }
   ReleaseDC(pDc);//释放picture控件的Dc
   return ;

(2)在VC6中加载图片
如果整个对话框没有什么其他,在onbutton中加入invalidate即可,系统会自动调用onpaint的

那么,在onpaint中加入如下语句(我的paint_bmp是一个bool变量,是用来判断是否要在picture控件中画图,因为我的对话框中还有别的控件)还要说明的一点,在对话框中加入picture控件时,type不需要改成位图,直接是边框就可以啦,这样你可以限制图片的显示大小,如果是位图type,是改变不了大小的,所以加载进来的图片就那么大点

CPaintDC dc(this); // device context for painting

if(PAINT_BMP)
{
CPaintDC dc(this);
SendMessage(WM_ICONERASEBKGND,(WPARAM) dc.GetSafeHdc(),0);

int cxIcon=GetSystemMetrics(SM_CXICON);
int cyIcon=GetSystemMetrics(SM_CYICON);

CRect rect;
GetClientRect(&rect);

int x=(rect.Width()-cxIcon+1)/2;
int y=(rect.Height()-cyIcon+1)/2;

dc.DrawIcon(x,y,m_hIcon);

}
else
{
CDialog::OnPaint();
}
HBITMAP bmpHandle=(HBITMAP)LoadImage(NULL,path_filter,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
CBitmap bmpPicture;
CDC mdcPicture;
CBitmap *bmpFromHandle=bmpPicture.FromHandle(bmpHandle);
BITMAP bm;
    ::GetObject(bmpHandle,sizeof(bm),&bm);
int height=bm.bmHeight;
int width=bm.bmWidth;

CRect rctPicture,rctPicture1;
m_pic_origin.GetWindowRect(&rctPicture);
    CDC *pDC=m_pic_origin.GetDC();

if(height<=rctPicture.Height()&&width<=rctPicture.Width())
{
mdcPicture.CreateCompatibleDC(&dc);
CBitmap *bmpPrevious=mdcPicture.SelectObject(bmpFromHandle);

ScreenToClient(&rctPicture);
dc.BitBlt(rctPicture.left,rctPicture.top,rctPicture.Width(),rctPicture.Height(),&mdcPicture,0,0,SRCCOPY);

dc.SelectObject(bmpPrevious);
DeleteObject(bmpHandle);
}

else
{
float xscale=(float)rctPicture.Width()/(float)width;
float yscale=(float)rctPicture.Height()/(float)height;

float ScaleIndex=(xscale<=yscale)?xscale:yscale;
mdcPicture.CreateCompatibleDC(&dc);
  CBitmap *bmpPrevious=mdcPicture.SelectObject(bmpFromHandle);

ScreenToClient(&rctPicture);
  rctPicture1=CRect(rctPicture.TopLeft(),CSize((int)width*ScaleIndex,(int)height*ScaleIndex));
  //dc.BitBlt(rctPicture1.left,rctPicture1.top,rctPicture1.Width(),rctPicture1.Height(),&mdcPicture,0,0,SRCCOPY);
       dc.StretchBlt(rctPicture1.left,rctPicture1.top,rctPicture1.Width(),rctPicture1.Height(),&mdcPicture,0,0,width,height,SRCCOPY);
  dc.SelectObject(bmpPrevious);
  DeleteObject(bmpHandle);

}

另外,还要说明的一点就是BitBlt和StretchBlt,后者是可以调整图片大小的随着控件的大小,而前者就是一个点一个点的话,前者只会将你的图片裁剪而不会调整(缩放)

原文:https://blog.csdn.net/m0_37702666/article/details/79791253

关于HBITMAP,CBITMAP,BITMAP的转换以及图像显示的一点归纳相关推荐

  1. HBITMAP与BITMAP 的区别 BMP图像的格式

    HBITMAP 是句柄: BITMAP 是实例: typedef struct tagBITMAP { /* bm */ int bmType;//必须是BM int bmWidth;//指定位图的宽 ...

  2. HBITMAP与BITMAP 的区别 BMP图像的格式

    HBITMAP   是句柄:   BITMAP    是实例: typedef struct tagBITMAP {  /* bm */     int     bmType;//必须是BM      ...

  3. RGB和Bitmap互相转换

    RGB和Bitmap互相转换 2017年05月09日 21:48:44 阅读数:2619 之前做人脸识别的时候遇到一个问题,把RGB数据转换成Bitmap.所以决定写一个RGB和Bitmap互相转换的 ...

  4. Mat转HBITMAP CBitmap

    本转换代码从opencv源码 imshow中提取并改造而成 源码来自与opencv4库 与openCV3有些许不同这里给出内部用到的转换代码 ,拿到HBITMAP句柄后 再使用 CBitmap m_b ...

  5. [视觉实战案例]Qt下BYTE、QImage、HObject、Mat等图像格式的转换和图像显示方法

    文章目录 一.图像格式间相互转换 1.BYTE转QImage.HObject和Mat 2.QImage.HObject和Mat的相互转换 二.图像显示方法 1.QLabel显示QPixmap图像 2. ...

  6. Android App开发之位图加工Bitmap中转换位图的像素色彩、裁剪内部区域、利用矩阵变换位图的讲解及实战(附源码和演示)

    需要图片集和源码请点赞关注收藏后评论区留言~~~ 一.转换位图的像素色彩 给图片添加装饰物,只是在局部变换,如果想让图片一边保持轮廓一边改变色彩,就要深入图像的每个像素点,将这些像素点统统采取某种算法 ...

  7. Laya 将传统的bitmap字体 转换成 Laya可以识别的字体

    转码 常用的fnt字体 是无法在Laya里直接运行的 需要转码 如果你的项目需要从别的引擎转到 Laya 那么fnt资源就需要重新导出了 这里提供一个工具 可以直接将 通用的fnt字体转换成laya的 ...

  8. byte字节流和bitmap互相转换

    /**把byte字节流转成bitmap* @param bytes*/ public void byteToBitmap(byte[] bytes) {BitmapFactory.Options op ...

  9. 3. GDI+ Bitmap和GDI HBITMAP互转

    之所以将GDI+ Bitmap和GDI HBITMAP互转单独挑出来写下,是因为实际应用中经常我们需要GDI和GDI+换用,特别是需要兼顾效率和渲染效果的场合,更是通常使用GDI+做平滑/抗锯齿,用G ...

最新文章

  1. 人民搜索,该怎么说你才好
  2. 怎么才能钓到产品经理妹子?|PMCAFF
  3. [React Native] 解析JSON文件
  4. HDU 1427 速算24点
  5. Node.js与Sails~Model数据模型
  6. 不进行格式化将U盘快速转换为NTFS格式
  7. 【编译原理】为什么编程语言中,标识符不能以数字开头?
  8. 汉诺塔java程序_Java编写一个汉诺塔的过程
  9. ajax向后台传递list参数
  10. memcached 安装与简单实用使用
  11. 转:12种JavaScript MVC框架之比较
  12. 升级Windows 2003域的唯一DC
  13. 房产电商新变数:阿里加码易居
  14. php blowfish 解密,php blowfish加密解密算法
  15. 中国人民大学与加拿大女王大学金融硕士让你在疫情下的学习有更多的选择
  16. Mysql创建用户给局域网内用户使用,开放权限,开放ip访问。
  17. Google Earth Engine(GEE)——Landsat ETM+ to OLI 协调
  18. 您应该购买哪款Apple Watch?
  19. questasim的傻瓜式安装与仿真教程
  20. SOI round0 题解

热门文章

  1. jsoncpp去掉多余字符_Python超详细的字符串用法大全
  2. vivado链接不上开发板最有可能原因
  3. 冒泡算法代码java_java版本的冒泡算法
  4. wpf开发仿真3d软件_web 3d 与仿真
  5. android studio 修改包名_android逆向笔记之初学者常用adb命令
  6. 拆解苹果iPhone11
  7. 一种基于谷歌浏览器加载activex控件的解决方法与流程技术_Office控件使用总踩雷?畅写Office带你云端飞行...
  8. 计算机关机又自动重启,为什么w7电脑关机后自动重启_w7电脑关机后自动重启怎么解决...
  9. ipython使用 python3,2019-04-29 python/ipython设置默认python3
  10. 学计算机的事物多线程看不懂,看不懂CPU?学会看CPU只需明白这5点,如此简单!...