关于HBITMAP,CBITMAP,BITMAP的转换以及图像显示的一点归纳
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的转换以及图像显示的一点归纳的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CABAC之手把手教你编码
- 下一篇: OpenCv2 学习笔记(1) Mat创