依赖于设备的位图(DDB) ,CreateCompatibleBitmap用法
DDB(Device-dependent bitmap)依赖于具体设备,这主要体现在以下两个方面:
-
DDB的颜色模式必需与输出设备相一致。例如,如果当前的显示设备是256色模式,那么DDB必然也是256色的,即一个像素用一个字节表示。
-
在256色以下的位图中存储的像素值是系统调色板的索引,其颜色依赖于系统调色板。
由于DDB高度依赖输出设备,所以DDB只能存在于内存中,它要么在视频内存中,要么在系统内存中。
11.3.1 DDB的创建
MFC的CBitmap类封装了DDB。该类提供了几个函数用来创建DDB:
BOOL LoadBitmap( LPCTSTR lpszResourceName );
BOOL LoadBitmap( UINT nIDResource );
该函数从资源中载入一幅位图,若载入成功则返回TRUE。资源位图实际上是一个DIB,该函数在载入时把它转换成了DDB。
BOOL CreateBitmap( int nWidth, int nHeight, UINT nPlanes, UINT nBitcount, const void* lpBits );
该函数用来创建一幅空白的DDB。参数nWidth和nHeight以像素为单位说明了位图的宽度和高度。nPlanes是DDB的色平面数,nBitcount是每个色平面的颜色位数。一般来说,nPlanes为1,而nBitcount代表DDB中每个像素值所占的位数,但在创建16色DDB时,nPlanes为4,而nBitcount为1。参数lpBits指向存储像素阵列的数组,该数组应该逐行存储位图的每个像素值。注意,数组中每行像素的数目必需是偶数个字节,如果是奇数,则应该用0补足。若创建成功函数返回TRUE。
BOOL CreateCompatibleBitmap( CDC* pDC, int nWidth, int nHeight );
该函数创建一个与指定设备上下文兼容的DDB。参数pDC指向一个设备上下文,nWidth和nHeight是DDB的尺寸。若创建成功函数返回TRUE。
可以调用CBitmap的成员函数GetBitmap来查询DDB的各种属性(如尺寸):
int GetBitmap( BITMAP* pBitMap );
该函数用来获得与DDB有关的信息,参数pBitMap指向一个BITMAP结构。BITMAP结构的定义为:
typedef struct tagBITMAP {
LONG bmType; //必需为0
LONG bmWidth; //位图的宽度(以像素为单位)
LONG bmHeight; //位图的高度(以像素为单位)
LONG bmWidthBytes; //每一扫描行所需的字节数,应是偶数
WORD bmPlanes; //色平面数
WORD bmBitsPixel; //色平面的颜色位数
LPVOID bmBits; //指向存储像素阵列的数组
} BITMAP;
11.3.2 DDB的用途
DDB的主要用途是保存位图。要保存的位图可以来自资源位图,也可以是一个绘图的结果。
前面说过,在256色以下的显示模式中,DDB中的像素值是系统调色板的索引。一般在系统调色板中除了保留的20种静态颜色外,其它表项都有可能被应用程序改变。如果DDB中有一些像素值是指向20种静态颜色以外的颜色,那么该位图的颜色将是不稳定的。因此,DDB不能用来长期存储色彩丰富的位图。如果位图使用的大部分颜色都是20种保留色,则该位图可以用CBitmap对象保存在内存中。例如,用CDC::LoadBitmap载入的资源位图一般都是颜色较简单的位图,对于那些颜色比较丰富的位图,只有使用下面将要介绍的DIB才能长期保存。
在窗口中显示DDB的方法有些特别,其过程分以下几步:
构建一个CDC对象,然后调用CDC::CreateCompatibleDC创建一个兼容的内存设备上下文。
调用CDC::SelectObject将DDB选入内存设备上下文中。
调用CDC::BitBlt或CDC::StretchBlt将DDB从内存设备上下文中输出到窗口的设备上下文中。
调用CDC::SelectObject把原来的DDB选入到内存设备上下文中并使新DDB脱离出来。
下面这段代码在视图中显示了一个DDB:
void CMyView::OnDraw( CDC* pDC)
{
. . .
CDC MemDC;
CBitmap *oldBmp;
BITMAP bmpInfo;
int bmWidth,bmHeight;
MemDC.CreateCompatibleDC(pDC);
oldBmp=MemDC.SelectObject(&m_Bitmap); //m_Bitmap是一个CBitmap对象
m_Bitmap.GetBitmap(&bmpInfo); //获取位图的尺寸
bmWidth=bmpInfo.bmWidth;
bmHeight=bmpInfo.bmHeight;
pDC->BitBlt(0,0,bmWidth,bmHeight,&MemDC,0,0,SRCCOPY);
MemDC.SelectObject(oldBmp); //使位图m_Bitmap脱离设备上下文
. . .
}
函数CDC::BitBlt的声明为:
BOOL BitBlt( int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, DWORD dwRop );
该函数把源设备上下文中的位图复制到本身的设备上下文中,两个设备上下文可以是内存设备上下文,也可以是同一个设备上下文。参数x和y是目的矩形的逻辑坐标,参数nWidth和nHeight说明了目的矩形及源位图的宽和高。pSrcDC指向源设备上下文,xSrc和ySrc说明了源矩形相对于源位图左上角的偏移。参数dwRop指定了光栅操作(ROP)代码,一些常用的ROP代码如表11.2所示。
表11.2 常用的ROP代码
ROP码
含义
BLACKNESS
输出黑色
DSTINVERT
反转目的位图
MERGECOPY
用与操作把图案(Pattern)与源位图融合起来
MERGEPAINT
用或操作把反转的源位图与目的位图融合起来
NOTSRCCOPY
把源位图反转然后拷贝到目的地
NOTSRCERASE
用或操作融合源和目的位图,然后再反转
PATCOPY
把图案拷贝到目的位图中
PATINVERT
用异或操作把图案与目的位图相融合
PATPAINT
用或操作融合图案和反转的源位图,然后用或操作把结果与目的位图融合
SRCAND
用与操作融合源位图和目的位图
SRCCOPY
把源位图拷贝到目的位图
SRCERASE
先反转目的位图,再用与操作将其与源位图融合
SRCINVERT
用异或操作融合源位图和目的位图
SRCPAINT
用或操作融合源位图和目的位图
WHITENESS
输出白色
函数CDC::StretchBlt的声明为:
BOOL StretchBlt( int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop );
该函数把位图从源矩形拷贝到目的矩形中,如果源和目的矩形尺寸不同,那么将缩放位图的功能以适应目的矩形的大小。函数的大部分参数与BitBlt的相同,但多了两个参数nSrcWidth和nSrcHeight用来指定源矩形的宽和高。
DDB的一个重要用途是用作设备上下文的显示表面。每一个设备上下文都包含有一个DDB,该位图实际上是在显示设备的缓冲区中(如视频内存),我们可以把它看做设备上下文的显示表面,设备上下文用GDI函数绘图实际上就是修改它所包含的DDB(显示表面)的过程。
普通的设备上下文都是在屏幕上绘图的,而使用内存设备上下文则可以在系统内存中绘制图形。内存设备上下文是一种特殊的设备上下文,它将系统内存用作显示表面。程序可以使用内存设备上下文预先在系统内存中绘制复杂的图形,然后再快速地将其复制到实际的设备上下文的显示表面上,而绘制图形的结果仍保存在内存设备上下文的DDB中。
内存设备上下文缺省的DDB是一个1×1的单色位图,如此小的显示表面显然是没有用的,因此程序一般要为内存设备对象选择一个合适大小的彩色DDB。
下面这段代码创建了一个内存设备上下文,并在其包含的DDB中画了一个灰色实心矩形,然后再把DDB输出到屏幕上。
void CMyView::OnDraw(CDC* pDC)
{
. . .
CDC MemDC;
CBitmap bm,*oldBmp;
MemDC.CreateCompatibleDC(pDC); //创建一个兼容的内存设备上下文
bm.CreateCompatibleBitmap(pDC,100,50); //创建一个兼容的DDB
oldBmp=MemDC.SelectObject(&bm);
MemDC.SelectStockObject(BLACK_PEN);
MemDC.SelectStockObject(GRAY_BRUSH);
MemDC.Rectangle(0,0,50,50); //在DDB中画一个矩形
pDC->BitBlt(0,0,100,50,&MemDC,0,0,SRCCOPY);
MemDC.SelectObject(oldBmp); //使位图bm对象脱离设备上下文
. . .
}
在上面的代码中,绘图的结果保存在位图bm中,一旦调用MemDC.SelectObject(oldBmp)使位图bm脱离设备上下文,该位图就可以被其它对象使用。
下面是别人的一段代码,我无法理解CreateCompatibleBitmap函数的意义。兼容位图到里是做什么的?不明白!
CPaintDC dc(this); // 用于绘制的设备上下文
CRect rcClient;
GetClientRect(&rcClient);
//构造内存DC,用于画图
CDC m_MemDC;
m_MemDC.CreateCompatibleDC(&dc);
CBitmap btScreen;
btScreen.CreateCompatibleBitmap(&dc, rcClient.Width(), rcClient.Height());
m_MemDC.SelectObject(&btScreen);
btScreen.DeleteObject();
//这里画图
...
dc.BitBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), &m_MemDC, 0, 0, SRCCOPY);
m_MemDC.DeleteDC();
/////////////////////////////////////////////
一)
在上面代码中,如果我将
btScreen.CreateCompatibleBitmap(&dc, rcClient.Width(), rcClient.Height());
换成
btScreen.LoadBitmap(IDB_BITMAP1);
能达到同样的效果吗?
二)
btScreen.CreateCompatibleBitmap(&dc, rcClient.Width(), rcClient.Height());
m_MemDC.SelectObject(&btScreen);
CreateCompatibleBitmap创建一幅兼容位图后将该容易位图选入DC中,这个兼容位图到里是个什么图片?我发现,将该语句屏蔽后,程序运行后显示有些地方是黑的。不知道为什么。
三)
我想知道,CreateCompatibleBitmap到里创建了一幅什么位图啊?这个函数里面根本就没有填入任何位图信息嘛,难道它创建的是一幅空位图吗?它有什么意思啊?平常都是用LoadBitmap来创建位图的,真不知道什么时候该用CreateCompatibleBitmap函数,对这个函数一点都不理解,希望有高手能详细指点一下,重分答谢!
网友回复:记不清楚了,大概是每个新建的内存兼容DC里选中的位图都是1*1的灰度图,不创建一个兼容位图选进去的话,现实意义上说这个DC不可用(往上面bitblt)
网友回复:兼容位图是位图的各种信息与设备相兼容,主要是颜色位数要相同。
新创建的位图所有像素值都是0,通常是黑色。
兼容位图主要用于与设备相互复制图象,最常见的就是“双缓冲”绘图方式。
网友回复:CreateCompatibleBitmap用法
创建一幅与设备有关位图,它与指定的设备场景兼容
内存设备场景即与彩色位图兼容,也与单色位图兼容。这个函数的作用是创建一幅与当前选入hdc中的场景兼容。对一个内存场景来说,默认的位图是单色的。倘若内存设备场景有一个DIBSection选入其中,这个函数就会返回DIBSection的一个句柄。如hdc是一幅设备位图,那么结果生成的位图就肯定兼容于设备(也就是说,彩色设备生成的肯定是彩色位图)
如果nWidth和nHeight为零,返回的位图就是一个1×1的单色位图
一旦位图不再需要,一定用DeleteObject函数释放它占用的内存及资源
网友回复:一:可以,但是要注意位图的大小。
二:内存DC默认的位图是1x1单色位图,必须选入屏幕兼容的位图(也可以是其它格式)才能绘制、显示对应格式的颜色;
三:CreateCompatibleBitmap创建的位图是空的,一般初始化为黑色(和操作系统有关),关键是复制了参数中dc的位图格式。