[翻譯]-WinCE 程序設計 (3rd 版)--2.3 位圖

位圖

位圖是一種圖形化對象,用於在設備環境裏創建、繪製、操縱和接收圖片。從[開始按鈕]上的小Winodws標誌到標題欄上的[關閉]按鈕,位圖在Windows裏無處不在。位圖可以看作是一種由像素數組構成的圖片,這些像素可以在屏幕上進行繪製。和所有圖片一樣,位圖有自己的高度和寬度。也提供方法來判斷位圖使用什麼顏色。最後,位圖也是一個描述位圖中每個像素的位(bits)數組。

習慣上,Windows下的位圖被劃分成兩種類型:設備相關位圖(DDBs)和設備無關位圖(DIBs)。DDBs是一種和具體DC的特性有緊密關係的位圖,不容易在有不同特性的DC上繪製。DIBs則相反,它與具體設備無關,因此需要攜帶足夠的信息以便於在任何設備上準確的繪製。

Windwos CE包含了許多在其它Windows版本里可以使用的位圖函數。不同之處包括只有Windows CE才支持的一種新的四色格式和對DIBs不同的操縱方式。

設備相關位圖
可以使用CreateBitmap函數來創建設備相關位圖,函數原型如下:
HBITMAP CreateBitmap (int nWidth, int nHeight, UINT cPlanes, UINT cBitsPerPel, CONST VOID *lpvBits);
nWidth和nHeight表示位圖的尺寸。cPlanes是一個歷史產物,當時顯示器採用不同的硬件平面來實現像素裏的每個顏色。對Windows CE來說,該參數必須是1。cBitspPerPel表示每個像素使用的位數。顏色數是cBitspPerPel的2次冪。在Windows CE下,允許使用的是1、2、4、8、16和24。正如我說過的,4色位圖是Windows CE特有的,其它Windows 平臺不則不支持。

最後一個參數是指向位圖位數的指針。在Windows CE下,位數總是按壓縮像素格式排列的。也就是,每個像素按字節存儲成一系列的比特位,下一個像素緊接上一個。位數組的第一個像素是位圖左上角的像素。像素沿位圖頂行排列,隨後是第二行,依次類推。位圖每行必須是雙字(4字節)對齊排列。爲了對齊下一行,可在行尾使用0來填充。圖2-5演示了這種排列方式,圖中展示了一個126*64像素的位圖,每個像素使用8位。
 
圖2-5(略) 位圖裏的字節佈局

函數CreateCompatibleBitmap,其原型如下:
HBITMAP CreateCompatibleBitmap (HDC hdc, int nWidth, int nHeight);
用該函數可以創建一個格式與傳入的設備環境兼容的位圖。所以如果設備環境是四色DC,創建的位圖也是一個四色位圖。當您要在屏幕上操縱圖片時,使用該函數很就很方便,因爲該函數可以很容易創建一個與屏幕直接顏色兼容的空位圖。

設備無關位圖
設備無關位圖和設備相關位圖之間的基本差異是存儲成DIBs的圖象有自己的顏色信息。自從使用BMP作爲擴展名的Windows 3.0起,幾乎每個位圖文件都含有在Windows裏創建DIB時所需要的信息。

在Windows早期,寫程序手工讀DIB文件並把數據轉換爲位圖是程序員必備的技能。現在,這個煩冗的任務可以通過Windows CE特有的函數SHLoadDIBitmap來完成,函數原型如下:
HBITMAP SHLoadDIBitmap (LPCTSTR szFileName);
該函數直接從位圖文件裏裝載位圖並提供位圖句柄。在Windows XP裏可以使用帶LR_LOADFROMFILE參數標誌的LoadImage函數來完成同樣的處理,但Windows CE下的LoadImage不支持這個標誌。

DIB片段
雖然Windows CE裏很容易裝載位圖文件,但有時您必須讀屏幕上圖象、操縱圖象以及將圖象重畫到屏幕上。這是DIBs比DDBs更好一些的地方之一。雖然設備相關位圖的位數據可以獲取得到,但緩衝區的格式直接依賴於屏幕格式。而通過使用DIB,或者更準確地說,通過使用DIB片段,您的程序可以把位圖讀到預定義格式的緩衝區裏,而不用擔心顯示設備的格式。

雖然從Windows 3.0起就不斷加入許多DIB創建函數,但Windows CE只支持XP中的一部分DIB函數。CreateDIBSection是這些函數中的第一個:
HBITMAP CreateDIBSection (HDC hdc, const BITMAPINFO *pbmi,  UINT iUsage, void *ppvBits,
                          HANDLE hSection, DWORD dwOffset);
因爲他們是相當晚才加到Win32 API裏的,所以DIB片段對程序員來說可能是比較新鮮的。使用DIB片段是爲了改進Winodows NT上直接操縱位圖的應用程序性能。簡而言之,DIB片段允許程序員在直接訪問位圖位數據時,選擇一個設備環境裏的DIB。爲達到這個目的,DIB片段將一個緩衝區與內存DC結合到一起,該緩衝區同時包含了該DC的位數據。因爲圖象是映射到一個DC的,所以可以使用其它圖形函數調用來修改圖片。同時,DC裏的DIB格式的原始位數據可以被直接操縱。能改進在NT上的性能固然是很好,但對Window CE程序員來說,能夠簡化位圖的使用和操作位圖的內容纔是最有價值的。

該函數中最重要的參數是指向BITMAPINFO結構的指針。該結構描述了設備無關位圖的佈局和顏色構成,該結構包含一個BITMAPINFOHEADER結構和一個代表位圖使用的調色板的RGBQUAD數組。

BITMAPINFOHEADER定義如下
typedef struct tagBITMAPINFOHEADER{
    DWORD biSize;
    LONG biWidth;
    LONG biHeight;
    WORD biPlanes;
    WORD biBitCount;
    DWORD biCompression;
    DWORD biSizeImage;
    LONG biXPelsPerMeter;
    LONG biYPelsPerMeter;
    DWORD biClrUsed;
    DWORD biClrImportant;
} BITMAPINFOHEADER;
如你所見,該結構包含的信息遠多於傳給CreateBitmap的參數。第一個域是該結構的尺寸,必須由調用者填充,用於區別由OS/2管理器沿襲來的BITMAPCOREINFOHEADER結構。biWidth, biHeight, biPlanes,和biBitCount都和CreateBitmap裏的同名參數類似,但有一個例外,biHeight的正負號指定了位數組的組織排列方式。如果biHeight是正數,位數組按由上到下的格式排列,這一點和CreateBitmap相同。如果biHeight是負數,位數組則按由下到上的格式排列,也就是位圖的底部行定義在該位數組的首位。和CreateBitmap一樣,biPlanes必須設置爲1。

biCompression指出位數組使用的壓縮方式。Windows CE裏,允許使用的標誌有,BI_RGB,指出緩衝區沒有壓縮;BI_BITFIELDS,指出像素格式被定義在顏色表的頭三個入口裏。biSizeImage用於指出位數組的大小。但是,當使用BI_RGB標誌時,biSizeImage可以設置爲0,表示用BITMAPINFOHEADER結構裏提供的尺寸(dimensions )和像素的位數來計算數組的大小。

biXPelsPerMeter和biYPelsPerMeter提供圖片的準確尺寸信息。但是對於CreateBIBSection來說,這些參數可以設置爲0。biClrUsed指出實際使用的調色板裏的顏色數。在256色圖片裏,調色板有256個入口,但畏途自身可能只需要大約100個不同的顏色。這個域幫助調色板管理器--Windows管理顏色匹配的部件--將系統調色板裏的顏色同位圖要求的顏色進行匹配。biClrImportant進一步指出真正需要的顏色。對更多顏色的位圖,這兩個域設置爲0,表示使用所有顏色並且所有顏色都重要。

前面提到過,BITMAPINFOHEADER結構之後是RGBQUAD結構數組。該結構定義如下:
typedef struct tagRGBQUAD { /* rgbq */
    BYTE rgbBlue;
    BYTE rgbGreen;
    BYTE rgbRed;
    BYTE rgbReserved;
} RGBQUAD

該結構允許有紅藍綠各256級色度(shade )。雖然用該結構可以創建幾乎任何色度,但設備上實際渲染的顏色是受設備能顯示的顏色的限制的。

總體來看,RGBQUAD結構數組描述了DIB的調色板。調色板是位圖裏的顏色列表。如果位圖有調色板,位圖數組的每個入口包含的就不再是顏色,而是包含每個像素顏色的調色板索引。雖然對單色位圖來說是多餘的,但當在彩色設備上繪製彩色位圖時,調色板就相當重要了。例如,雖然256色位圖中每個像素一個字節,但該字節指向一個代表紅綠藍色的24位值。所以儘管256色位圖只能包含256個不同的顏色,但由於是使用24位調色板入口進行顏色繪製的,因而這些顏色中的每個都可使用出的1千6百萬種顏色中的一個。爲了方便在32位中使用,每個只包含24位顏色信息的調色板入口都被擴充到32位寬度了,這也是RGBQUAD名字的來源。(譯者注:QUAD有四個一套的意思)

CreateDIBSection剩餘的四個參數中只有兩個用於Windows CE。IUsage指出調色板裏的顏色是如何被繪製的。如果該參數是DIB_RGB_COLORS,表示位圖裏的位數據包含了每個像素的全部RGB顏色信息;DIB_PAL_COLORS,表示位圖像素包含DC裏當前選擇的調色板的索引。PpvBits 是指向構成位圖圖象的位數據的指針。最後兩個參數,hSection和dwOffset,Windows CE不支持它們,必須設置爲0。在Windows的其它版本里,它們允許使用內存映射文件來給出位數據。因爲Windows CE不支持內存映射文件,所以它們不能被CreateDIBSection支持。

GetDIBColorTable和SetDIBColorTable是管理DIB調色板的兩個函數,它們的原型如下:
UINT GetDIBColorTable (HDC hdc, UINT uStartIndex,    UINT cEntries, RGBQUAD *pColors);

UINT SetDIBColorTable (HDC hdc, UINT uStartIndex,  UINT cEntries, RGBQUAD *pColors);
對這兩個函數來說,uStartIndex指出將被設置或者查詢的調色板的第一個入口。CEntries指出有多少調色板入口將改變。指向RGBQUAD數組的指針是用於設置(對SetDIBColorTable)或者查詢(對GetDIBColorTable)的顏色數組。

繪製位圖
能夠創建和裝載位圖固然很好,但如果您創建的位圖不能繪製在屏幕上,那就沒什麼大用處。繪製位圖可能並不是您想象的那麼簡單。位圖被繪製到屏幕DC之前,必須先將位圖選進一個DC,再將其複製到屏幕設備環境裏。雖然這個過程聽起來可能有點費解,但這是有合理的原因的。

把位圖選擇到一個設備環境的過程與把邏輯字體選擇到設備環境的過程類似。下面讓我們把理想變成現實吧。正如Windows要爲請求的字體找到最可能匹配的字體一樣,位圖選擇過程也必須爲位圖要求的顏色找到匹配的設備上可用的顏色。只有在這個過程完成後,位圖才能繪製到屏幕上。爲了幫助完成這一中間步驟,Windows提供了一個替身DC—內存設備環境。

要創建內存設備環境,可以使用函數CreateCompatibleDC:
HDC CreateCompatibleDC (HDC hdc);
該函數創建一個與當前屏幕DC兼容的內存DC。一旦創建成功,可以使用您以前用來選擇邏輯字體的SelectObject函數將源位圖選進這個內存DC。最後,用BitBlt 或StretchBlt將位圖從內存DC複製到屏幕DC。

位圖函數的主力是
BOOL BitBlt (HDC hdcDest, int nXDest, int nYDest, int nWidth,   int nHeight, HDC hdcSrc, int nXSrc,  int nYSrc,  DWORD dwRop);

BitBlt函數發音爲“bit blit”,它是一個有意思的函數,它在設備環境上操作,而不是內存裏,它有時是一個很特別的函數。第一個參數是位圖即將被複制到其上的目的設備環境的句柄。接下來的4個參數規定了位圖最終位於的目的矩形的位置和大小。接下來的3個參數規定了源設備環境的句柄以及源圖象左上角在該DC裏的位置。

最後一個參數dwRop規定圖象如何從源設備環境複製到目的設備環境。ROP代碼規定了源位圖和當前目的設備如何組合來產生最終圖片。ROP代碼爲SRCOPY,表示簡單複製源圖象。ROP代碼爲SRCPAINT,表示源圖象和目的之間進行或操作。ROP代碼爲SRCINVERT,表示複製一個邏輯反轉圖象,本質上是一個負的源圖象。一些ROP代碼還將當前選擇的畫刷(brush)一起作爲計算結果圖象的因素。ROP代碼很多,所以這裏不可能覆蓋全,要獲得全部列表,請參考Windows CE編程文檔。

下面的代碼片段總結了如何繪製位圖:

// Create a DC that matches the device.
hdcMem = CreateCompatibleDC (hdc);
  
// Select the bitmap into the compatible device context.
hOldSel = SelectObject (hdcMem, hBitmap);
  
// Get the bitmap dimensions from the bitmap.
GetObject (hBitmap, sizeof (BITMAP), &bmp);
  
// Copy the bitmap image from the memory DC to the screen DC.
BitBlt (hdc, rect.left, rect.top, bmp.bmWidth, bmp.bmHeight,
        hdcMem, 0, 0, SRCCOPY);
  
// Restore original bitmap selection and destroy the memory DC.
SelectObject (hdcMem, hOldSel);
DeleteDC (hdcMem);

創建內存設備環境,即將被繪製的位圖被選進該DC。因爲您可能沒有存儲即將被繪製的位圖尺寸,通常可以調用GetObject來獲得。GetObject返回關於圖形對象的信息,在本例中是一個位圖。可以用這個很有用的函數來查詢字體和其它圖象對象的信息。接下來,使用BitBlit將位圖複製進屏幕DC。爲了清理,需要將位圖從內存設備環境中取消選擇,並使用DeleteDC將該內存DC刪除。不要將DeleteDC同ReleaseDC混淆,ReleaseDC是釋放一個顯示DC。DeleteDC只應該和CreateCompatibleDC一起使用,ReleaseDC只應該和GetDC或GetWindowsDC一起使用。

用StretchBlt除了複製位圖,還可以拉伸或者壓縮位圖。該函數原型如下:
BOOL StretchBlt (HDC hdcDest, int nXOriginDest, int nYOriginDest,  int nWidthDest, int nHeightDest, HDC hdcSrc,  int nXOriginSrc, int nYOriginSrc, int nWidthSrc,  int nHeightSrc, DWORD dwRop);
StretchBlt裏的參數和BitBlt裏的基本相同,但是有一點例外的是現在可以指定源圖象的寬度和高度。同樣的,這裏的ROP代碼規定了源和目的之間如何組合來產生最終圖象。

Windows CE還有另外一個位圖函數TransparentImage,原型如下:
BOOL TransparentImage (HDC hdcDest, LONG DstX, LONG DstY, LONG DstCx,
                       LONG DstCy, HANDLE hSrc, LONG SrcX, LONG SrcY,
                       LONG SrcCx, LONG SrcCy, COLORREF TransparentColor);

該函數同StretchBlt類似,但有兩個很重要的例外。首先,您可以指定位圖裏作爲透明色的顏色。當把位圖複製到目標中時,位圖裏透明色的像素不被複制。第二個不同是hSrc參數要麼是設備環境要麼是位圖句柄,該參數允許您不必理會在屏幕上繪製圖象前必須將源圖象選進一個設備環境的要求。TransparentImage與Windows 2000中的TransparentBlt函數基本相同,除了TransparetBlt不能直接使用位圖作爲源圖象以外。

和其它版本的Windows一樣,Windows CE還支持2個其它blit函數:PatBlt和MaskBlt。PatBlt函數將當前選擇的畫刷同目的DC裏當前圖象進行組合,產生結果圖象。我在本章後面會談到畫刷。MaskBlt函數與BitBlt類似,但包含一個掩碼圖象,用來提供只繪製源圖象的一部分到目的DC裏的功能。

發佈了2 篇原創文章 · 獲贊 1 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章