3. DDB位圖編程
先看DDB加載按鈕的單擊事件代碼:
void CBitMapExampleDlg::OnLoadddbpic() { 1: CBitmap bmpDraw; 2: bmpDraw.LoadBitmap( IDB_LOADED_BITMAP );//裝入要加載的DDB位圖 3: BITMAP bmpInfo; 4: bmpDraw.GetBitmap( &bmpInfo ); //獲取要加載DDB位圖的尺寸 5: CDC memDC;//定義一個兼容DC 6: CClientDC dc( this ); 7: memDC.CreateCompatibleDC( &dc );//創(chuàng)建兼容DC 8: CBitmap* pbmpOld = memDC.SelectObject( &bmpDraw );//保存原有DDB,并選入新DDB入DC
9: dc.BitBlt( 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, &memDC, 0, 0, SRCCOPY );
10: memDC.SelectObject( pbmpOld );//選入原DDB } |
上述代碼將產(chǎn)生如圖1所示的效果,位圖被安置在對話框(0,0)坐標(biāo)開始的位置上。
我們來逐行解析上述代碼是怎樣產(chǎn)生圖1的效果的。
第1、2行定義了一個CBitmap對象,并調(diào)用其成員函數(shù)LoadBitmap加載工程中的位圖資源IDB_LOADED_BITMAP。第3、4行定義了BITMAP結(jié)構(gòu)體的實例并調(diào)用CBitmap的成員函數(shù)GetBitmap獲得位圖信息,BITMAP結(jié)構(gòu)體定義在<wingdi.h>頭文件中,其形式為:
/* Bitmap Header Definition */ typedef struct tagBITMAP { LONG bmType; //必需為0 LONG bmWidth; //位圖的寬度(以像素為單位) LONG bmHeight; //位圖的高度(以像素為單位) LONG bmWidthBytes; //每一掃描行所需的字節(jié)數(shù),應(yīng)是偶數(shù) WORD bmPlanes; //色平面數(shù) WORD bmBitsPixel; //色平面的顏色位數(shù) LPVOID bmBits; //指向存儲像素陣列的數(shù)組 } BITMAP, *PBITMAP, NEAR *NPBITMAP, FAR *LPBITMAP; |
第5~8行的作用是:構(gòu)建一個CDC對象,調(diào)用CDC::CreateCompatibleDC創(chuàng)建一個兼容的內(nèi)存設(shè)備上下文,接著調(diào)用CDC::SelectObject將DDB選入內(nèi)存設(shè)備上下文中。
第9行調(diào)用函數(shù)CDC::BitBlt繪制位圖,CDC::BitBlt的原型為:
CDC::BitBlt(int x, int y, int nWidth, int nHeight, CDC *pSrcDC, int xSrc, int ySrc, DWORD dwRop) |
CDC::BitBlt執(zhí)行的操作為將源DC中位圖復(fù)制到目的DC中。其中前四個參數(shù)為目的區(qū)域的坐標(biāo)(x,y)及長度和寬度(Width, nHeight),第五個參數(shù)是源DC指針,接下來的參數(shù)是源DC中的起始坐標(biāo),最后一個參數(shù)為光柵操作的類型。
第10行調(diào)用CDC::SelectObject把原來的DDB選入到內(nèi)存設(shè)備上下文中并使新DDB脫離出來。
與CDC::BitBlt對應(yīng)的還有另一個函數(shù)CDC::StretchBlt,它具有縮放功能,其原型為:
BOOL CDC::StretchBlt(int x, int y, int nWidth, int nHeight, CDC *pSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop); |
該函數(shù)把位圖從源矩形拷貝到目的矩形中,如果源和目的矩形尺寸不同,那么將縮放位圖的功能以適應(yīng)目的矩形的大小。函數(shù)的大部分參數(shù)與BitBlt的相同,但多了兩個參數(shù)nSrcWidth和nSrcHeight用來指定源矩形的寬和高。
如果我們將函數(shù)CBitMapExampleDlg::OnLoadddbpic() 中的第9行改為:
CRect clientRect; GetClientRect(&clientRect); //獲得對話框窗口的大小 dc.StretchBlt(0, 0, clientRect.right, clientRect.bottom, &memDC, 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, SRCCOPY); |
則單擊加載按鈕后的對話框如圖2所示,位圖被拉伸至整個對話框的范圍。
CDC::BitBlt和dc.StretchBlt函數(shù)中的dwRop參數(shù)較為有用,它定義光柵操作的類型。請看"DDB位圖"父菜單下"標(biāo)記"子菜單單擊事件的消息處理函數(shù)代碼:
void CBitMapExampleDlg::OnMarkDdbpic() { CBitmap bmpDraw; bmpDraw.LoadBitmap(IDB_YESKY_BITMAP); //裝入天極網(wǎng)logo DDB位圖資源 BITMAP bmpInfo; bmpDraw.GetBitmap(&bmpInfo); //獲取天極網(wǎng)logo位圖的尺寸
CDC memDC; //定義一個兼容DC CClientDC dc(this); memDC.CreateCompatibleDC(&dc); //創(chuàng)建DC
CBitmap *pbmpOld = memDC.SelectObject(&bmpDraw); //保存原有DDB,并選入天極網(wǎng)logo位圖入DC dc.BitBlt(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, &memDC, 0, 0, SRCAND); memDC.SelectObject(pbmpOld); //選入原DDB } |
單擊該按鈕后,將產(chǎn)生如圖3的效果,天極網(wǎng)的logo被透明地添加到了位圖中!
圖3 在DDB位圖中加入天極網(wǎng)logo |
能產(chǎn)生這個效果的原因在于我們在代碼行:
dc.BitBlt ( 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, &memDC, 0, 0, SRCAND ); |
中使用了參數(shù)SRCAND(不同于先前代碼中SRCCOPY,它僅僅意味著復(fù)制源位圖到目的位圖),它的含義為源和目的間進(jìn)行AND操作。我們不知道天極網(wǎng)的編輯同志是怎么為文章中的圖片加logo的,有可能他們就使用了具有自動AND功能的圖像加logo批處理軟件。的確,我們可以利用例程中的原理寫一個批處理軟件,一次對一堆圖片自動添加logo。
參數(shù)dwRop除了可以為SRCAND和SRCCOPY外,還可以有如下取值:
BLACKNESS:輸出區(qū)域為黑色
DSTINVERT:反轉(zhuǎn)目的位圖
MERGECOPY:用與操作把圖案(Pattern)與源位圖融合起來
MERGEPAINT:用或操作把反轉(zhuǎn)的源位圖與目的位圖融合起來
NOTSRCCOPY:把源位圖反轉(zhuǎn)然后拷貝到目的地
NOTSRCERASE:用或操作融合源和目的位圖,然后再反轉(zhuǎn)
PATCOPY:把圖案拷貝到目的位圖中
PATINVERT:用異或操作把圖案與目的位圖相融合
PATPAINT:用或操作融合圖案和反轉(zhuǎn)的源位圖,然后用或操作把結(jié)果與目的位圖融合
SRCERASE:先反轉(zhuǎn)目的位圖,再用與操作將其與源位圖融合
SRCINVERT:用異或操作融合源位圖和目的位圖
SRCPAINT:用或操作融合源位圖和目的位圖
WHITENESS:輸出區(qū)域為白色
合理利用這些取值將幫助我們制作出特定要求的圖像處理軟件。
從上述實例我們可以看出,在VC中使用CBitmap類,必須將位圖放入工程的資源中,并使用類 CBitmap的成員函數(shù)LoadBitmap加載之,再通過CDC類的成員函數(shù)BitBlt進(jìn)行DC拷貝等操作達(dá)到顯示的目的。CBitmap有顯示的不足:
?。?) 位圖需要放入工程資源中,這將導(dǎo)致工程的可執(zhí)行文件變大;
?。?) 因為位圖需放入工程資源中,而資源中不能無窮無盡地包含位圖,應(yīng)用程序無法自適應(yīng)地選取其它位圖,能使用的位圖十分有限的;
?。?) 類CBitmap只是DDB位圖操作API的封裝,不能獨立于平臺。
DIB位圖則可以解決上述問題,其特點是以.BMP位圖文件格式存儲獨立于平臺的圖像數(shù)據(jù),下面我們來詳細(xì)分析。