位圖資料






緒言返回目錄


位圖在Windows系統平臺中是一種很常見的圖像格式,如果從保存圖像的性能上來講它不是最好的,JPG、GIF格式都超過它,但是由於它是微軟公司制定的標準,並且已嵌入了操作系統,所以它就顯得很重要了。以下的內容是我根據VC5.0的聯機幫助翻譯而來的,有些地方我加入了自己的觀點(都已用括號表明),因爲我對位圖的知識掌握的也不是太深,所以可能有些地方翻譯的不是太準確,甚至是錯誤,如果哪位高手發現了,請不吝賜教。同時,我也希望這份資料能對那些想了解位圖的朋友有所幫助,那是我編譯這份資料的最大願望!



關於位圖 (About Bitmap)返回目錄


位圖是能被選入設備描述表(DC)的七種目標之一,其餘的六種目標是:筆(pen)、刷(brush)、字體(font)、區域(region)、邏輯調色板(logical palette)、和路徑(path)。在微軟Win32應用程序界面(API)中,控制面板應用程序就是一種使用位圖的程序,當用戶爲桌面選擇壁紙的時候,實質上他選擇的就是位圖,Windows系統將根據這張位圖來繪製桌面。從用戶的角度來看,位圖只是一個矩形的圖像,而在開發者的眼中,位圖則是一個結構的集合體。它可能包含以下的一些元素:

* 一個描述圖像信息的結構,比如圖像的大小(寬、高)、位數組的尺寸、創建這張圖片的設備的分辯率,等等。
* 一個邏輯調色板
* 一個位數組,它定義了像素值與邏輯調色板的關係(譯者注:如果該圖片有邏輯調色板的話,如果沒有調色板,位數組中的像素值將直接代表各像素的顏色分量)。

下面的圖例可用於說明一個位圖的真實位數組內容:

在前面這個範例中,圖像是創建於一個VGA的顯示器,這種設備使用了一個16色的調色板,而一個16色的調色板至少需要4位的索引值才能表示(2^4),所以,在位圖的位數組中,每個像素都是用4位(半個字節)來表示索引值的。
注意:在上面的位圖的中,Windows系統映射索引值到像素時是先從底掃描行開始,到頂掃描行結束的(掃描行是圖像中水平方向的一個單行的所有像素)。比如,位數組中的第一行(row 0)對應於圖像的最底行。這是因爲上面這張位圖是一張底到上型(bottom-up)的DIB(設備無關)位圖,這也是一種很普通的位圖。對於頂到下型的DIB以及DDB位圖來說,Windows系統映射索引值到像素時則是從頂掃描行開始的。

位圖的類型 (Bitmap Types)返回目錄

位圖一共有兩種類型,即:設備相關位圖(DDB)和設備無關位圖(DIB)。DDB位圖在早期的Windows系統(Windows 3.0以前)中是很普遍的,事實上它也是唯一的。然而,隨着顯示器製造技術的進步,以及顯示設備的多樣化,DDB位圖的一些固有的問題開始浮現出來了。比如,它不能夠存儲(或者說獲取)創建這張圖片的原始設備的分辯率,這樣,應用程序就不能快速的判斷客戶機的顯示設備是否適合顯示這張圖片。爲了解決這一難題,微軟創建了DIB位圖格式。

設備無關位圖 (Device-Independent Bitmap)

DIB位圖包含下列的顏色和尺寸信息:
* 原始設備(即創建圖片的設備)的顏色格式。
* 原始設備的分辯率。
* 原始設備的調色板
* 一個位數組,由紅、綠、藍(RGB)三個值代表一個像素。
* 一個數組壓縮標誌,用於表明數據的壓縮方案(如果需要的話)。

以上這些信息保存在BITMAPINFO結構中,該結構由BITMAPINFOHEADER結構和兩個或更多個RGBQUAD結構所組成。BITMAPINFOHEADER結構所包含的成員表明了圖像的尺寸、原始設備的顏色格式、以及數據壓縮方案等信息。RGBQUAD結構標識了像素所用到的顏色數據。

DIB位圖也有兩種形式,即:底到上型DIB(bottom-up),和頂到下型DIB(top-down)。底到上型DIB的原點(origin)在圖像的左下角,而頂到下型DIB的原點在圖像的左上角。如果DIB的高度值(由BITMAPINFOHEADER結構中的biHeight成員標識)是一個正值,那麼就表明這個DIB是一個底到上型DIB,如果高度值是一個負值,那麼它就是一個頂到下型DIB。注意:頂到下型的DIB位圖是不能被壓縮的。

位圖的顏色格式是通過顏色面板值(planes)和顏色位值(bitcount)計算得來的,顏色面板值永遠是1,而顏色位值則可以是1、4、8、16、24、32其中的一個。如果它是1,則表示位圖是一張單色位圖(譯者注:通常是黑白位圖,只有黑和白兩種顏色,當然它也可以是任意兩種指定的顏色),如果它是4,則表示這是一張VGA位圖,如果它是8、16、24、或是32,則表示該位圖是其他設備所產生的位圖。如果應用程序想獲取當前顯示設備(或打印機)的顏色位值(或稱位深度),可調用API函數GetDeviceCaps(),並將第二個參數設爲BITSPIXEL即可。
顯示設備的分辯率是以每米多少個像素來表明的,應用程序可以通過以下三個步驟來獲取顯示設備或打印機的水平分辯率:
1. 調用GetDeviceCaps()函數,指定第二個參數爲HORZRES。
2. 再次調用GetDeviceCaps()函數,指定第二個參數爲HORZSIZE。
3. 用第一個返回值除以第二個返回值。即:DetDeviceCaps(hDC,HORZRES)/GetDeviceCaps(hDC,HORZSIZE);

應用程序也可以使用相同的三個步驟來獲取設備的垂直分辯率,不同之處只是要將HORZRES替換爲VERTRES,把HORZSIZE替換爲VERTSIZE,即可。

調色板是被保存在一個RGBQUAD結構的數組中,該結構指出了每一種顏色的紅、綠、藍的分量值。位數組中的每一個索引都對應於一個調色板項(即一個RGBQUAD結構),應用程序將根據這種對應關係,將像素索引值轉換爲像素RGB值(真實的像素顏色)。應用程序也可以通過調用GetDeviceCaps()函數來獲取當前顯示設備的調色板尺寸(將該函數的第二個參數設爲NUMCOLORS即可)。

Win32 API支持位數據的壓縮(只對8位和4位的底到上型DIB位圖)。壓縮方法是採用運行長度編碼方案(RLE),RLE使用兩個字節來描述一個句法,第一個字節表示重複像素的個數,第二個字節表示重複像素的索引值。有關壓縮位圖的詳細信息請參見對BITMAPINFOHEADER結構的解釋。

應用程序可以從一個DDB位圖創建出一個DIB位圖,步驟是,先初始化一些必要的結構,然後再調用GetDIBits()函數。不過,有些顯示設備有可能不支持這個函數,你可以通過調用GetDeviceCaps()函數來確定一下(GetDeviceCaps()函數在調用時指定RC_DI_BITMAP作爲RASTERCAPS的標誌)。

應用程序可以用DIB去設置顯示設備上的像素(譯者注:也就是顯示DIB),方法是調用SetDIBitsToDevice()函數或調用StretchDIBits()函數。同樣,有些顯示設備也有可能不支持以上這兩個函數,這時你可以指定RC_DIBTODEV作爲RASTERCAPS標誌,然後調用GetDeviceCaps()函數來判斷該設備是否支持SetDIBitsToDevice()函數。也可以指定RC_STRETCHDIB作爲RASTERCAPS標誌來調用GetDeviceCaps()函數,來判斷該設備是否支持StretchDIBits()函數。

如果應用程序只是要簡單的顯示一個已經存在的DIB位圖,那麼它只要調用SetDIBitsToDevice()函數就可以。比如一個電子表格軟件,它可以打開一個圖表文件,在窗口中簡單的調用SetDIBitsToDevice()函數,將圖形顯示在窗口中。但如果應用程序要重複的繪製位圖的話,則應該使用BitBlt()函數,因爲BitBlt()函數的執行速度要比SetDIBitsToDevice()函數快很多。

設備相關位圖 (Device-Dependent Bitmaps)

設備相關位圖(DDB)之所以現在還被系統支持,只是爲了兼容舊的Windows 3.0軟件,如果程序員現在要開發一個與位圖有關的程序,則應該儘量使用或生成DIB格式的位圖。

DDB位圖是被一個單個結構BITMAP所描述,這個結構的成員標明瞭該位圖的寬度、高度、設備的顏色格式等信息。

DDB位圖也有兩種類型,即:可廢棄的(discardable)DDB和不可廢棄的(nondiscardable)DDB。可廢棄的DDB位圖就是一種當系統內存缺乏,並且該位圖也沒有被選入設備描述表(DC)的時候,系統就會把該DDB位圖從內存中清除(即廢棄)。不可廢棄的DDB則是無論系統內存多少都不會被系統清除的DDB。API函數CreateDiscardableBitmap()函數可用於創建可廢棄位圖。而函數CreateBitmap()、CreateCompatibleBitmap()、和CreateBitmapIndirect()可用於創建不可廢棄的位圖。

應用程序可以通過一個DIB位圖而創建一個DDB位圖,只要先初始化一些必要的結構,然後再調用CreateDIBitmap()函數就可以。如果在調用該函數時指定了CBM_INIT標誌,那麼這一次調用就等價於先調用CreateCompatibleBitmap()創建當前設備格式的DDB位圖,然後又調用SetDIBits()函數轉換DIB格式到DDB格式。(可能有些設備並不支持SetDIBits()函數,你可以指定RC_DI_BITMAP作爲RASTERCAPS的標誌,然後調用GetDeviceCaps()函數來判斷一下)。



位圖、設備描述表、和繪圖表面 (Bitmaps, Device Contexts, and Drawing Surfaces) 返回目錄

設備描述表(DC)是一個定義圖形目標的數據結構,包括圖形的屬性、映射模式等信息。應用程序可以調用CreateDC()函數來創建一個DC,它也可以調用GetDC()函數來獲取一個窗口的DC。

繪圖表面

在應用程序獲得一個DC句柄之前,窗口將先選擇一個“繪圖表面”到DC中。如果應用程序是在一個VGA的顯示設備上調用的CreateDC()函數,那麼它獲得的DC繪圖表面尺寸就是640×480像素。如果應用程序是調用的GetDC()函數,則繪圖表面的尺寸就等於窗口客戶區的尺寸。

當應用程序使用由CreateDC()函數或GetDC()函數返回的DC句柄來進行繪圖操作時(即用這個DC來調用繪圖函數,如LineTo()函數),被請求的操作將出現在已選入該DC的繪圖表面上。

兼容設備描述表 (Compatible Device Contexts)

先將圖形在內存中畫好,再一次性的輸出到真實的顯示設備上要比多次向顯示設備上輸出圖形要快,並且程序更容易設計。爲此,微軟專門提供了一種特殊的設備描述表,稱爲兼容設備描述表(Compatible Device Context)(譯者注:也叫作內存設備描述表)。Windows系統把兼容DC視爲一種存在於內存中的虛擬設備。實質上兼容DC就是內存中的一個數組,應用程序可以把位圖的顏色數據(即像素)保存於兼容DC中。

應用程序可以調用CreateCompatibleDC()函數來創建一個兼容設備描述表,該函數將返回一個DC句柄,你可以象使用真實設備DC一樣來使用這個兼容DC。Windows系統在創建這種DC時,附加的也創建了一個1位的位圖(即單色位圖),並在CreateCompatibleDC()函數返回之前將該位圖選入兼容DC中。所以應用程序在使用這個兼容DC之前,應先替換掉這個1位的位圖。方法是,先調用CreateBitmap()、CreateBitmapIndirect()、或CreateCompatibleBitmap()函數來創建一個你所需要的位圖(由你指定位圖的尺寸及位深度),並獲得一個位圖句柄,然後調用SelectObject()函數將這個位圖句柄選入兼容DC。在位圖句柄被選入兼容DC之後,Windows系統將用一個足夠大的位數組來替換掉原來的1位位圖的位數組(譯者注:請注意保存這個1位的位圖,在繪圖操作結束後還要選回)。此時,你就可以用該兼容DC來進行繪圖操作了(比如:直線、曲線、文本、區域等操作),繪製的結果將被保存在兼容DC中的位數組中。但這個時候,這些結果你並不能馬上看到,你應該調用BitBlt()函數將保存於兼容DC位數組中的圖像拷貝到真實設備的繪圖表面上(請注意,在調用BitBlt()函數時,要將兼容DC作爲源DC,而將真實設備DC作爲目標DC來調用)。

當你顯示一個有調色板的DIB或DDB時(原始設備具有調色板),你可以通過適當的安排系統調色板來加快圖像的顯示速度。首先用NUMRESERVED作參數調用GetDeviceCaps()函數,來獲取系統中保留的顏色個數。然後調用GetSystemPaletteEntries()函數,並用相應的系統顏色填充邏輯調色板開頭和結尾的NUMRESERVED/2個調色板項。比如NUMRESERVED的返回值是20,則你必需用系統顏色填充邏輯調色板開頭和結尾各10個項的調色板數據。然後再用位圖的調色板來填充剩餘的調色板項(這種調色板項必需設置PC_NOCOLLAPSE標誌)。有關調色板和顏色的資料請參閱VC聯機幫助中Colors一節。



位圖的旋轉 (Bitmap Rotation) 返回目錄

Windows提供了一個函數,用於將矩形的位圖拷貝到一個平行四邊形中,這個函數就是PlgBlt()。在轉換時,要將矩形位圖DC作爲源DC,而將平行四邊形DC作爲目標DC。有關旋轉和World units(譯者注:這個詞未譯出)的資料請參見VC聯機幫助中Coordinate Spaces 和 Transformations 中的內容。



位圖的比例縮放 (Bitmap Scaling) 返回目錄

Win32 API也提供了一個按比例縮放位圖的函數,它就是StretchBlt()。它可以將源設備描述表(DC)中的矩形位圖傳送到目標設備描述表中。但不同於BitBlt()函數,StretchBlt()允許應用程序指定源、目標位圖的尺寸。如果應用程序指定的目標位圖尺寸比源位圖尺寸小,則系統將壓縮源位圖以符合目標位圖尺寸。同時,你也可以指定該函數的壓縮方式,使用SetStretchBitMode()函數。當目標位圖的尺寸大於源位圖時,系統將拉伸源位圖(即擴大像素的顏色範圍)以符合要求。



作爲畫刷的位圖 (Bitmaps as Brushes) 返回目錄

Win32 API中有幾個函數是使用已選入DC中的畫刷來進行位圖操作的,比如:PatBlt()函數可在窗口的一個矩形區域中複製畫刷,而FloodFill()函數則可以在窗口的一個非矩形區域中複製畫刷(這個非矩形區域可以用指定顏色來圈定)。

PatBlt()函數的名字其實是一個縮寫,全稱應該是“圖樣塊傳送”(PATtern BLock Transfer, 縮寫後就是PatBlt),從這個名字上看,它好像只是簡單的複製畫刷(或叫圖樣),直到填充完指定的矩形之後就結束了,其實這個函數可沒有這麼簡單,它在複製畫刷之前,將根據光珊操作碼(raster operation,縮寫是ROP)來組合圖樣中的像素與目標DC中相同位置上的像素而形成最終的圖像。光珊操作碼(ROP)在組合的過程中起到了非常重要的作用,實質上ROP是一種位操作符,一共有256種,PatBlt()函數可以接受那些需要圖樣和目標位圖的ROP。下面的表格列出了該函數經常用到的5個ROP:

 ROP  描述 PATCOPY  拷貝圖樣到目標位圖中 PATINVERT  用圖樣的像素或(即位操作OR)目標位圖 DSTINVERT  將目標位圖的像素值取反(即非目標圖的像素值) BLACKNESS  將所有的輸出都設爲二進制的0 WHITENESS  將所有的輸出都設爲二進制的1

不同於PatBlt()函數,FloodFill()函數只是將選入DC的畫刷簡單的重複複製到一個由用戶用指定顏色圈定的不規則區域中(填充滿爲止)。它不接受ROP命令。

 



位圖的存儲 (Bitmap Storage) 返回目錄

如果用戶想將位圖保存到一個文件中,那麼應用程序必需爲該文件取一個以.BMP爲後綴的擴展名,然後將位圖以Windows位圖文件格式保存到該文件當中。Windows位圖文件格式由幾部分組成,下表說明:

其中第一個結構BITMAPFILEHEADER包括了一些對位圖文件的大致說明,比如:位圖文件的標誌“BM”、位圖文件的尺寸、位數組的偏移等信息。第二個結構BITMAPINFOHEADER則指明瞭位圖圖像的寬度、高度、顏色格式(位面數,位深度)、壓縮標誌、原始設備分辯率等信息。再接下來的是RGBQUAD結構數組,它裏面放置的是位圖的調色板數據,每一個結構描述一個調色板項(包括紅、綠、藍的分量值)。(譯者注:有些位圖沒有這個RGBQUAD數組,比如16位、24位、32位位圖。而且有些位圖文件將該數組所佔空間移做它用,如16位、32位位圖的BI_BITFIELD格式就將該空間作爲三色掩碼的存放處,編程時應注意區別)。

下面的表顯示了一個BMP文件的實際內容:

0000 42 4d 76 02 00 00 00 00 00 00 76 00 00 00 28 00
0010 00 00 20 00 00 00 20 00 00 00 01 00 04 00 00 00
0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0030 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80
0040 00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80
0050 00 00 80 80 80 00 c0 c0 c0 00 00 00 ff 00 00 ff
0060 00 00 00 ff ff 00 ff 00 00 00 ff 00 ff 00 ff ff
0070 00 00 ff ff ff 00 00 00 00 00 00 00 00 00 00 00
0080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 09 00
0090 00 00 00 00 00 00 11 11 01 19 11 01 10 10 09 09
00a0 01 09 11 11 01 90 11 01 19 09 09 91 11 10 09 11
00b0 09 11 19 10 90 11 19 01 19 19 10 10 11 10 09 01
00c0 91 10 91 09 10 10 90 99 11 11 11 11 19 00 09 01
00d0 91 01 01 19 00 99 11 10 11 91 99 11 09 90 09 91
00e0 01 11 11 11 91 10 09 19 01 00 11 90 91 10 09 01
00f0 11 99 10 01 11 11 91 11 11 19 10 11 99 10 09 10
0100 01 11 11 11 19 10 11 09 09 10 19 10 10 10 09 01
0110 11 19 00 01 10 19 10 11 11 01 99 01 11 90 09 19
0120 11 91 11 91 01 11 19 10 99 00 01 19 09 10 09 19
0130 10 91 11 01 11 11 91 01 91 19 11 00 99 90 09 01
0140 01 99 19 01 91 10 19 91 91 09 11 99 11 10 09 91
0150 11 10 11 91 99 10 90 11 01 11 11 19 11 90 09 11
0160 00 19 10 11 01 11 99 99 99 99 99 99 99 99 09 99
0170 99 99 99 99 99 99 00 00 00 00 00 00 00 00 00 00
0180 00 00 00 00 00 00 90 00 00 00 00 00 00 00 00 00
0190 00 00 00 00 00 00 99 11 11 11 19 10 19 19 11 09
01a0 10 90 91 90 91 00 91 19 19 09 01 10 09 01 11 11
01b0 91 11 11 11 10 00 91 11 01 19 10 11 10 01 01 11
01c0 90 11 11 11 91 00 99 09 19 10 11 90 09 90 91 01
01d0 19 09 91 11 01 00 90 10 19 11 00 11 11 00 10 11
01e0 01 10 11 19 11 00 90 19 10 91 01 90 19 99 00 11
01f0 91 01 11 01 91 00 99 09 09 01 10 11 91 01 10 91
0200 99 11 10 90 91 00 91 11 00 10 11 01 10 19 19 09
0210 10 00 99 01 01 00 91 01 19 91 19 91 11 09 10 11
0220 00 91 00 10 90 00 99 01 11 10 09 10 10 19 09 01
0230 91 90 11 09 11 00 90 99 11 11 11 90 19 01 19 01
0240 91 01 01 19 09 00 91 10 11 91 99 09 09 90 11 91
0250 01 19 11 11 91 00 91 19 01 00 11 00 91 10 11 01
0260 11 11 10 01 11 00 99 99 99 99 99 99 99 99 99 99
0270 99 99 99 99 99 90


下面的表格說明各結構在上面的位圖中所佔的位置,可對照查看:

 結構   對應的字節範圍 BITMAPFILEHEADER   0x00 - 0x0D   BITMAPINFOHEADER   0x0E - 0x35   RGBQUAD array   0x36 - 0x75   Color-index array   0x76 - 0x275 (譯者注:Color-index array實際上就是位圖的位數組)

 



使用位圖 (Using Bitmap) 返回目錄

捕獲圖像 (Capturing an Image) 返回目錄

你可以用位圖來捕獲圖像,並且可以將已捕獲的圖像保存到文件中,或是在窗口的其他位置顯示該圖像。在某些應用程序中,有些時候你也必需臨時性的保存屏幕上的圖像,比如在一個繪圖程序中,如果用戶選擇了放大命令,那麼你必需先保存當前屏幕上的圖像,然後將圖像放大,當用戶再返回正常圖像時,你就可以用原來保存的圖像恢復到屏幕上了。

要想保存屏幕上的圖像,你的應用程序必需先調用CreateCompatibleDC()函數來創建一個兼容於當前顯示設備的DC,然後你再調用CreateCompatibleBitmap()函數來創建一個適當尺寸的位圖,並把該位圖選入上面那個DC中(使用SelectObject()函數)。當兼容設備描述表被創建,並且適當尺寸的位圖也被選入了該DC之後,你就可以捕獲圖像了。Win32 API提供了BitBlt()函數來捕獲圖像,該函數起到了一個位塊傳輸的作用—就是將源位圖的位數據拷貝到目標位圖中。因爲該函數是在兩個位圖間傳輸數據,所以你可能以爲它的入口參數是兩個位圖的句柄,但實際情況可不是這樣,在BitBlt()函數的入口參數中你找不到位圖句柄的參數,它實際上是通過設備描述表(DC)來進行操作的,源位圖和目標位圖的句柄都必需被選入源DC和目標DC中。在BitBlt()調用結束之後,源位圖的數據就被拷貝到目標位圖中了,你如果想顯示這個圖像,可再次調用BitBlt()函數,並把原來的目標DC作爲源DC,把一個窗口DC(或打印機DC)作爲目標DC即可。

下面的範例代碼演示了怎樣創建兼容DC、怎樣創建位圖、怎樣將位圖選入DC、以及怎樣用BitBlt()函數捕捉圖像(注:該段代碼將捕獲整個的桌面圖像)。

/*  * Create a normal DC and a memory DC for the entire screen. The  * normal DC provides a "snapshot" of the screen contents. The  * memory DC keeps a copy of this "snapshot" in the associated  * bitmap.  */  hdcScreen = CreateDC("DISPLAY", NULL, NULL, NULL); hdcCompatible = CreateCompatibleDC(hdcScreen);  /* Create a compatible bitmap for hdcScreen. */  hbmScreen = CreateCompatibleBitmap(hdcScreen,                      GetDeviceCaps(hdcScreen, HORZRES),                      GetDeviceCaps(hdcScreen, VERTRES));  if (hbmScreen == 0)     errhandler("hbmScreen", hwnd);  /* Select the bitmaps into the compatible DC. */  if (!SelectObject(hdcCompatible, hbmScreen))     errhandler("Compatible Bitmap Selection", hwnd);          /* Hide the application window. */          ShowWindow(hwnd, SW_HIDE);          /*          * Copy color data for the entire display into a          * bitmap that is selected into a compatible DC.          */          if (!BitBlt(hdcCompatible,                0,0,                bmp.bmWidth, bmp.bmHeight,                hdcScreen,                0,0,                SRCCOPY))          errhandler("Screen to Compat Blt Failed", hwnd);          /* Redraw the application window. */          ShowWindow(hwnd, SW_SHOW);  

 



縮放圖像 (scaling an Image) 返回目錄

有一些應用程序(比如繪圖軟件)需要對圖像進行放大或縮小處理,這時,應用程序就可以通過調用StretchBlt()函數來達到目的。與BitBlt()函數相同,StretchBlt()函數也是將源DC中的位圖拷貝到目標DC中。但是,與BitBlt()函數不同的是,在StretchBlt()函數的入口參數中,應用程序可以指定源位圖和目標位圖的尺寸。如果指定的源位圖尺寸大於指定的目標位圖尺寸,則位圖將被壓縮,反之,位圖將被放大。

如果指定的目標位圖尺寸小於源位圖尺寸,StretchBlt()函數將根據當前伸縮模式來刪除一些像素,以使圖像變小。下面的表格是所有的伸縮模式代碼及它們的含意:

 伸縮模式碼 含意 BLACKONWHITE 把待刪除的像素與保留的像素進行邏輯與(AND)操作 WHITEONBLACK 把待刪除的像素與保留的像素進行邏輯或(OR)操作 COLORONCOLOR 徹底刪除待刪除的像素 HALFTONE  以目標的顏色數據逼近源像素

你如果想設置伸縮模式,可調用SetStretchBltMode()函數。


下面的範例代碼是從一個能將源圖像放大兩倍的程序中截取下來的(該應用程序使用的是缺省的伸縮模式,所以沒有使用SetStretchBltMode()函數)。

    hdcScaled = CreateCompatibleDC(hdcScreen);      hbmScaled = CreateCompatibleBitmap(hdcScreen,                     GetDeviceCaps(hdcScreen, HORZRES) * 2,                     GetDeviceCaps(hdcScreen, VERTRES) * 2);      if (hbmScaled == 0)         errhandler("hbmScaled", hwnd);      /* Select the bitmaps into the compatible DC. */      if (!SelectObject(hdcScaled, hbmScaled))         errhandler("Scaled Bitmap Selection", hwnd);      case WM_COMMAND:     /* message: command from application menu */        switch(wParam) {          case IDM_SCALEX1:             if (fBlt){                  fScaled = FALSE;                  hdcWin = GetDC(hwnd);                  BitBlt(hdcWin,                     0,0,                     bmp.bmWidth, bmp.bmHeight,                     hdcCompatible,                     0,0,                     SRCCOPY);                  ReleaseDC(hwnd, hdcWin);             }             break;          case IDM_SCALEX2:             if (fBlt){                  fScaled = TRUE;                  StretchBlt(hdcScaled,                      0, 0,                      bmp.bmWidth * 2, bmp.bmHeight * 2,                      hdcCompatible,                      0, 0,                      bmp.bmWidth, bmp.bmHeight,                      SRCCOPY);                   hdcWin = GetDC(hwnd);                  BitBlt(hdcWin,                     0,0,                     bmp.bmWidth, bmp.bmHeight,                     hdcScaled,                     0,0,                     SRCCOPY);                  ReleaseDC(hwnd, hdcWin);             }             break; 


存儲一幅圖像 (Storing an Image) 返回目錄

很多應用程序都需要將圖像保存到文件當中,比如繪圖程序要保存用戶所畫的圖片,電子表格程序要保存用戶的圖表,CAD軟件要保存圖形,等等。

如果你的應用程序想以位映射的方式保存圖像的話,你可以採用Windows操作系統的位圖格式來保存。步驟是,先初始化BITMAPINFO結構(由BITMAPINFOHEADER結構和RGBQUAD結構數組組成),然後填寫適當的數據用以說明待保存圖像的各種參數。最後將BITMAPFILEHEADER結構及BITMAPINFO結構和位數組寫入文件當中。

下面的範例代碼演示了怎樣初始化並填寫BITMAPINFOHEADER結構:

PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp) {    BITMAP bmp;     PBITMAPINFO pbmi;    WORD    cClrBits;      /* Retrieve the bitmap's color format, width, and height. */      if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp))         errhandler("GetObject", hwnd);       /* Convert the color format to a count of bits. */      cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);    if (cClrBits == 1)         cClrBits = 1;    else if (cClrBits <= 4)        cClrBits = 4;     else if (cClrBits <= 8)         cClrBits = 8;    else if (cClrBits <= 16)         cClrBits = 16;    else if (cClrBits <= 24)         cClrBits = 24;     else         cClrBits = 32;          /*      * Allocate memory for the BITMAPINFO structure. (This structure      * contains a BITMAPINFOHEADER structure and an array of RGBQUAD data      * structures.)           */          if (cClrBits != 24)         pbmi = (PBITMAPINFO) LocalAlloc(LPTR,                     sizeof(BITMAPINFOHEADER) +                     sizeof(RGBQUAD) * (2^cClrBits));          /*  There is no RGBQUAD array for the 24-bit-per-pixel format. */      else         pbmi = (PBITMAPINFO) LocalAlloc(LPTR,                     sizeof(BITMAPINFOHEADER));        /* Initialize the fields in the BITMAPINFO structure. */      pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);     pbmi->bmiHeader.biWidth = bmp.bmWidth;     pbmi->bmiHeader.biHeight = bmp.bmHeight;     pbmi->bmiHeader.biPlanes = bmp.bmPlanes;     pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;    if (cClrBits < 24)         pbmi->bmiHeader.biClrUsed = 2^cClrBits;       /* If the bitmap is not compressed, set the BI_RGB flag. */      pbmi->bmiHeader.biCompression = BI_RGB;          /*      * Compute the number of bytes in the array of color      * indices and store the result in biSizeImage.     */      pbmi->bmiHeader.biSizeImage = (pbmi->bmiHeader.biWidth + 7) /8                                   * pbmi->bmiHeader.biHeight                                   * cClrBits;          /*      * Set biClrImportant to 0, indicating that all of the      * device colors are important.     */      pbmi->bmiHeader.biClrImportant = 0;    return pbmi;  } 

 

下面的範例將演示怎樣打開一個文件,並拷貝數組、獲取調色板索引、初始化保留結構、關閉文件等操作:

void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi,                   HBITMAP hBMP, HDC hDC)  {      HANDLE hf;                  /* file handle */     BITMAPFILEHEADER hdr;       /* bitmap file-header */     PBITMAPINFOHEADER pbih;     /* bitmap info-header */     LPBYTE lpBits;              /* memory pointer */     DWORD dwTotal;              /* total count of bytes */     DWORD cb;                   /* incremental count of bytes */     BYTE *hp;                   /* byte pointer */     DWORD dwTmp;       pbih = (PBITMAPINFOHEADER) pbi;     lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);    if (!lpBits)          errhandler("GlobalAlloc", hwnd);      /*      * Retrieve the color table (RGBQUAD array) and the bits      * (array of palette indices) from the DIB.      */      if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight,                    lpBits, pbi, DIB_RGB_COLORS))         errhandler("GetDIBits", hwnd);      /* Create the .BMP file. */      hf = CreateFile(pszFile,                    GENERIC_READ | GENERIC_WRITE,                    (DWORD) 0,                    (LPSECURITY_ATTRIBUTES) NULL,                    CREATE_ALWAYS,                    FILE_ATTRIBUTE_NORMAL,                    (HANDLE) NULL);      if (hf == INVALID_HANDLE_VALUE)         errhandler("CreateFile", hwnd);      hdr.bfType = 0x4d42;        /* 0x42 = "B" 0x4d = "M" */      /* Compute the size of the entire file. */      hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +                  pbih->biSize + pbih->biClrUsed                  * sizeof(RGBQUAD) + pbih->biSizeImage);      hdr.bfReserved1 = 0;     hdr.bfReserved2 = 0;      /* Compute the offset to the array of color indices. */      hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +                     pbih->biSize + pbih->biClrUsed                     * sizeof (RGBQUAD);      /* Copy the BITMAPFILEHEADER into the .BMP file. */      if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER),        (LPDWORD) &dwTmp, (LPOVERLAPPED) NULL))        errhandler("WriteFile", hwnd);      /* Copy the BITMAPINFOHEADER and RGBQUAD array into the file. */      if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER)                   + pbih->biClrUsed * sizeof (RGBQUAD),                   (LPDWORD) &dwTmp, (LPOVERLAPPED) NULL))        errhandler("WriteFile", hwnd);      /* Copy the array of color indices into the .BMP file. */      dwTotal = cb = pbih->biSizeImage;     hp = lpBits;     while (cb > MAXWRITE)  {             if (!WriteFile(hf, (LPSTR) hp, (int) MAXWRITE,                           (LPDWORD) &dwTmp, (LPOVERLAPPED) NULL))                 errhandler("WriteFile", hwnd);             cb-= MAXWRITE;             hp += MAXWRITE;     }     if (!WriteFile(hf, (LPSTR) hp, (int) cb,          (LPDWORD) &dwTmp, (LPOVERLAPPED) NULL))            errhandler("WriteFile", hwnd);      /* Close the .BMP file. */      if (!CloseHandle(hf))            errhandler("CloseHandle", hwnd);      /* Free memory. */    GlobalFree((HGLOBAL)lpBits);} 

 



位圖操作函數列表 (Bitmap functions) 返回目錄

下面是操作位圖的各種函數,有興趣的朋友可查看Win32 API手冊。

 BitBlt() CreateBitmap() CreateBitmapIndirect() CreateCompatibleBitmap() CreateDIBitmap() CreateDIBSection() CreateDiscardableBitmap() ExtFloodFill() FloodFill() GetBitmapBits() GetBitmapDimensionEx() GetDIBColorTable() GetDIBits() GetPixel() GetStretchBltMode() LoadBitmap() MaskBlt() PatBlt() PlgBlt() SetBitmapBits() SetBitmapDimensionEx() SetDIBColorTable() SetDIBits() SetDIBitsToDevice() SetPixel() SetPixelV() SetStretchBltMode() StretchBlt() StretchDIBits()

 


與位圖相關的結構 (Bitmap Structures)

 BITMAP BITMAPCOREHEADER BITMAPCOREINFO BITMAPFILEHEADER BITMAPINFO BITMAPINFOHEADER COLORADJUSTMENT DIBSECTION RGBQUAD RGBTRIPLE SIZE
(譯者注:以上結構中,BITMAPINFO和BITMAPINFOHEADER的聯機幫助內容非常重要,如果你想深入瞭解BMP的結構,就應該仔細研讀一下)

 


與位圖相關的宏 (Bitmap Macros)

MAKEROP4

 

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1516532


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