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

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

- (1)定義位圖和設備描述表變量
CBitmap m_ChessBoard_Bitmap; //棋盤位圖對象 CBitmap m_BlackChess_Bitmap; //黑棋子位圖對象 CBitmap m_WhiteChess_Bitmap; //白棋子位圖對象 CBitmap m_Mask_Bitmap; //掩碼的位圖對象 CDC *pCurrent_DC; //當前窗口的DC指針 CDC m_BlackChess_DC; //粘貼黑棋子的DC CDC m_WhiteChess_DC; //粘貼黑棋子的DC CDC m_Complex_DC; //粘貼棋盤的DC CDC m_Mask_DC; //粘貼掩碼的DC
- (2)裝載位圖,將相應位圖邦定到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)獲取位圖結構
BITMAP m_ChessBoard_BITMAP; //棋盤的位圖結構實例
BITMAP m_BlackChess_BITMAP; //黑棋的位圖結構實例(黑棋與白棋一樣)
//將CBitmap對象的屬性賦予BITMAP結構體實例
m_ChessBoard_Bitmap.GetBitmap(&m_ChessBoard_BITMAP);
m_BlackChess_Bitmap.GetBitmap(&m_BlackChess_BITMAP);
- (4)創建與視頻設備描述表兼容的位圖設備描述表,將CBitmap對象選入最新創建的設備描述表中。
//為黑棋子DC申請一定的資源并綁定相應的棋子CBitmap對象 m_BlackChess_DC.CreateCompatibleDC(pCurrent_DC); m_BlackChess_DC.SelectObject(&m_BlackChess_Bitmap); //為白棋子DC申請一定的資源并綁定相應的棋子CBitmap對象 m_WhiteChess_DC.CreateCompatibleDC(pCurrent_DC); m_WhiteChess_DC.SelectObject(&m_WhiteChess_Bitmap); //為棋盤DC申請一定的資源并綁定相應的棋子CBitmap對象 m_Complex_DC.CreateCompatibleDC(pCurrent_DC); m_Complex_DC.SelectObject(&m_ChessBoard_Bitmap); //為掩碼DC申請一定的資源并初始綁定相應的CBitmap對象 m_Mask_DC.CreateCompatibleDC(pCurrent_DC); m_Mask_DC.SelectObject(&m_Mask_Bitmap);
- (5)設置白棋和黑棋為圓形的棋子,為將方形的棋子處理成圓形的棋子而將棋子圖片與掩碼圖片進行混合操作。
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)將棋子放置到棋盤上,即在相應的位置取得白色圓形棋子
int m_ChessPicture_Size = m_BlackChess_BITMAP.bmWidth;// 棋子圖片的寬度 //int Current_X為鼠標當前坐標點X坐標 // int Current_Y為鼠標當前坐標點Y坐標 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)得到本窗口的客戶區
CRect m_current_Wnd_Rect; //當前窗口的客戶端的矩形 GetClientRect(&m_current_Wnd_Rect); //得到本窗口的客戶區
- (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);