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