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中。
| 提示:有人可能會想到用BitBlt函數把繪圖結果從顯示設備拷貝到內存設備上下文中,這種方法可以工作,但有時會出錯。當源矩形被別的窗口遮住時,BitBlt會把別的窗口中的像素拷貝下來。 |
內存設備上下文缺省的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的位圖格式。
