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);