http://express.ruanko.com/ruanko-express_17/webpage/tech3.html
摘要:通過描述位圖內(nèi)存和視頻內(nèi)存原理,通過五子棋棋子透明顯示在棋盤上,說明VC++中位圖操作和如何實(shí)現(xiàn)透明位圖顯示。
1、實(shí)現(xiàn)原理
計(jì)算機(jī)視頻系統(tǒng)核心是內(nèi)存,位圖操作涉及到視頻內(nèi)存和位圖內(nèi)存。每次以及每一個(gè)圖形操作都會(huì)影響視頻內(nèi)存,位圖內(nèi)存為一塊類似于視頻內(nèi)存的RAM區(qū)域,它代表一個(gè)容納數(shù)據(jù)的內(nèi)存地址,二者極為相識(shí),區(qū)別在于位圖內(nèi)存看不到,而視頻內(nèi)存看的到。位圖駐留在位圖內(nèi)存中,如果被移到視頻內(nèi)存,則將顯示在監(jiān)視器上。
2、實(shí)現(xiàn)方法
繪制透明位圖是指繪制某一位圖中除指定顏色外的其余部分,我們稱這種顏色為透明色。通過將位圖的背景色指定為透明色,在繪制時(shí),不繪制這部分背景,而僅繪制圖像,這樣就可以將位圖中圖像透明地繪制到窗口上。如下圖1所示。

圖1 位圖透明顯示事例
繪制透明位圖的關(guān)鍵是創(chuàng)建一個(gè)掩碼位圖,掩碼位圖是一個(gè)單色位圖,它是位圖中圖像的一個(gè)單色剪影。在Windows編程中,繪圖都要用到設(shè)備描述表,需創(chuàng)建兩個(gè)內(nèi)存設(shè)備描述表:源位圖設(shè)備描述表和掩碼位圖設(shè)備描述表。源位圖設(shè)備描述表用來(lái)裝入源位圖,而掩碼位圖設(shè)備描述表用來(lái)裝入掩碼位圖。使用BitBlt執(zhí)行相應(yīng)光柵操作,將源位圖透明地繪制在目的位圖上。
在目的位圖上實(shí)現(xiàn)源位圖透明顯示步驟:
(1)首先,源位圖與掩碼位圖進(jìn)行SRCPAINT操作,即使用布爾OR操作將二者組合在一起;
(2)其次,目的位圖與掩碼位圖進(jìn)行MERGEPAINT操作,即使用布爾OR操作將取反后的掩碼位圖與目的位圖組合在一起;
(3)最后,目的位圖與源位圖進(jìn)行SRCAND操作,即使用布爾AND操作將二者組合在一起。
3、位圖透明顯示流程
(1)將位圖裝載到CBitmap對(duì)象;
(2)創(chuàng)建一個(gè)與視頻設(shè)備描述表兼容的位圖設(shè)備描述表;
(3)將CBitmap對(duì)象選入最新創(chuàng)建的設(shè)備描述表中;
(4)使用GetObject()填寫B(tài)ITMAP結(jié)構(gòu),以使了解位圖大小;
(5)源位圖與掩碼位圖進(jìn)行BitBlt(),使用SRCPAINT光柵操作碼,將二者合在一起,此部處理源位圖;
(6)目的位圖與掩碼位圖進(jìn)行BitBlt(),使用MERGEPAINT光柵操作碼,將二者合在一起;
(7)目的位圖與掩碼位圖進(jìn)行BitBlt(),使用SRCAND光柵操作碼,實(shí)現(xiàn)源位圖透明顯示。
4、事例
以五子棋為例,實(shí)現(xiàn)棋子在棋盤透明顯示,一般情況下,棋盤是帶有背景色的,棋子為黑白色(或者其它透明顏色)矩形,當(dāng)棋子粘貼到棋盤上時(shí),去除四個(gè)拐角,形成圓形棋子被放置到棋盤上,同時(shí)保留自身顏色,棋子中透明顏色都被保持不變。
下圖2為掩碼、棋子、棋盤的顯示,經(jīng)過BitBlt相應(yīng)光柵操作后,圖3就是白色棋子透明顯示。

- (1)定義位圖和設(shè)備描述表變量
CBitmap m_ChessBoard_Bitmap; //棋盤位圖對(duì)象 CBitmap m_BlackChess_Bitmap; //黑棋子位圖對(duì)象 CBitmap m_WhiteChess_Bitmap; //白棋子位圖對(duì)象 CBitmap m_Mask_Bitmap; //掩碼的位圖對(duì)象 CDC *pCurrent_DC; //當(dāng)前窗口的DC指針 CDC m_BlackChess_DC; //粘貼黑棋子的DC CDC m_WhiteChess_DC; //粘貼黑棋子的DC CDC m_Complex_DC; //粘貼棋盤的DC CDC m_Mask_DC; //粘貼掩碼的DC
- (2)裝載位圖,將相應(yīng)位圖邦定到CBitmap
m_ChessBoard_Bitmap.LoadBitmap(IDB_BITMAP_ChessBoard);// 棋盤 m_BlackChess_Bitmap.LoadBitmap(IDB_BITMAP_BlackChess);// 黑棋子 m_WhiteChess_Bitmap.LoadBitmap(IDB_BITMAP_WhiteChess);// 白棋子 m_Mask_Bitmap.LoadBitmap(IDB_BITMAP_Mask);// 掩碼
- (3)獲取位圖結(jié)構(gòu)
BITMAP m_ChessBoard_BITMAP; //棋盤的位圖結(jié)構(gòu)實(shí)例
BITMAP m_BlackChess_BITMAP; //黑棋的位圖結(jié)構(gòu)實(shí)例(黑棋與白棋一樣)
//將CBitmap對(duì)象的屬性賦予BITMAP結(jié)構(gòu)體實(shí)例
m_ChessBoard_Bitmap.GetBitmap(&m_ChessBoard_BITMAP);
m_BlackChess_Bitmap.GetBitmap(&m_BlackChess_BITMAP);
- (4)創(chuàng)建與視頻設(shè)備描述表兼容的位圖設(shè)備描述表,將CBitmap對(duì)象選入最新創(chuàng)建的設(shè)備描述表中。
//為黑棋子DC申請(qǐng)一定的資源并綁定相應(yīng)的棋子CBitmap對(duì)象 m_BlackChess_DC.CreateCompatibleDC(pCurrent_DC); m_BlackChess_DC.SelectObject(&m_BlackChess_Bitmap); //為白棋子DC申請(qǐng)一定的資源并綁定相應(yīng)的棋子CBitmap對(duì)象 m_WhiteChess_DC.CreateCompatibleDC(pCurrent_DC); m_WhiteChess_DC.SelectObject(&m_WhiteChess_Bitmap); //為棋盤DC申請(qǐng)一定的資源并綁定相應(yīng)的棋子CBitmap對(duì)象 m_Complex_DC.CreateCompatibleDC(pCurrent_DC); m_Complex_DC.SelectObject(&m_ChessBoard_Bitmap); //為掩碼DC申請(qǐng)一定的資源并初始綁定相應(yīng)的CBitmap對(duì)象 m_Mask_DC.CreateCompatibleDC(pCurrent_DC); m_Mask_DC.SelectObject(&m_Mask_Bitmap);
- (5)設(shè)置白棋和黑棋為圓形的棋子,為將方形的棋子處理成圓形的棋子而將棋子圖片與掩碼圖片進(jìn)行混合操作。
m_BlackChess_DC.BitBlt(0, 0, m_BlackChess_BITMAP.bmWidth, m_BlackChess_BITMAP.bmHeight, &m_Mask_DC, 0, 0, SRCPAINT); m_WhiteChess_DC.BitBlt(0, 0, m_BlackChess_BITMAP.bmWidth, m_BlackChess_BITMAP.bmHeight, &m_Mask_DC, 0, 0, SRCPAINT);
- (6)將棋子放置到棋盤上,即在相應(yīng)的位置取得白色圓形棋子
int m_ChessPicture_Size = m_BlackChess_BITMAP.bmWidth;// 棋子圖片的寬度 //int Current_X為鼠標(biāo)當(dāng)前坐標(biāo)點(diǎn)X坐標(biāo) // int Current_Y為鼠標(biāo)當(dāng)前坐標(biāo)點(diǎn)Y坐標(biāo) m_Complex_DC.BitBlt(Current_X - m_ChessPicture_Size/2, Current_Y – m_ChessPicture_Size/2, m_ChessPicture_Size, m_ChessPicture_Size, &m_Mask_DC, 0, 0, MERGEPAINT); m_Complex_DC.BitBlt(Current_X - m_ChessPicture_Size/2, Current_Y - m_ChessPicture_Size/2, m_ChessPicture_Size, m_ChessPicture_Size, &m_WhiteChess_DC, 0, 0, SRCAND);
- (7)得到本窗口的客戶區(qū)
CRect m_current_Wnd_Rect; //當(dāng)前窗口的客戶端的矩形 GetClientRect(&m_current_Wnd_Rect); //得到本窗口的客戶區(qū)
- (8)在OnPaint()中,將棋盤繪制在窗口上顯示
CPaintDC dc(this); // device context for painting //粘貼含有棋子的棋盤DC到該窗口上 dc.BitBlt(0, 0, m_current_Wnd_Rect.Width(), m_current_Wnd_Rect.Height(), &m_Complex_DC, 0, 0, SRCCOPY);