本文共 6635 字,大约阅读时间需要 22 分钟。
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->BITMAPCBitmap 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->HBITMAPHBITMAP hBitmap;
pbm->GetHBITMAP(NULL, &hBitmap);
6、BITMAP->CBitmapBitmap* 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 paintingif(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