GDI基本概念及思想
編寫代碼的一般步驟:先用CreateDC創(chuàng)建(或GetDC獲取)device content(DC),然后用GetObject獲?。ɑ蚴褂脛?chuàng)建object的函數(shù)創(chuàng)建)需要的object,并用SelectObject將獲取的object選入device content(DC),再使用object進(jìn)行相應(yīng)的畫圖操作,最后用SelectObject將原來的object重新選入DC,并delete或release刪除或釋放前面創(chuàng)建或獲取的DC。
1. 關(guān)于device context (DC)設(shè)備內(nèi)容:用來顯示位圖的地方.
四種設(shè)備內(nèi)容:顯示器設(shè)備內(nèi)容、打印機(jī)設(shè)備內(nèi)容、內(nèi)存設(shè)備內(nèi)容、Information設(shè)備內(nèi)容,常用的有顯示器DC和內(nèi)存DC.
Device Context Types: There are four types of DCs: display, printer, memory (or compatible), and information.
Device context | Description |
Supports drawing operations on a video display. | |
Supports drawing operations on a printer or plotter. | |
Supports drawing operations on a bitmap. | |
Supports the retrieval of device data. |
其中需要注意的一種類型是: Memory Device Contexts,將在bitmap處理中詳細(xì)介紹。
創(chuàng)建和獲取DC的相關(guān)函數(shù):
CreateDC,CreateCompatibleDC,GetDC,GetCurrentDC.
其中CreateCompatibleDC用于創(chuàng)建內(nèi)存設(shè)備內(nèi)容.
刷新、釋放和刪除DC的相關(guān)函數(shù):
ResetDC,ReleaseDC,DeleteDC.前者當(dāng)DC有變動(dòng)時(shí)用來重置DC,后者用來釋放使用萬完的DC.
DeleteDC與CreateDC對應(yīng)使用
ReleaseDC與GetDC對應(yīng)使用
2.關(guān)于graphical object(GDI objects):
包括:pen,brush,bitmap,palette,region,path.
獲取、選擇和刪除object的相關(guān)函數(shù):
GetObject,GetCurrentObject,SelectObject,DeleteObject。
關(guān)于SelectObject需要注意的地方:在使用完object后需要將原來默認(rèn)的object重新選入DC替換掉新的object,bitmap只可以選入"內(nèi)存DC",一個(gè)bitmap不能同時(shí)選入多個(gè)DC.
This function returns the previously selected object of the specified type. An application should always replace a new object with the original, default object after it has finished drawing with the new object. An application cannot select a bitmap into more than one DC at a time.
如果object是創(chuàng)建的,則使用完后必須刪除創(chuàng)建的object,創(chuàng)建object的一些函數(shù)如下:
下面重點(diǎn)介紹GDI中關(guān)于bitmap的處理:
關(guān)于Bitmap和Device Context:
1.關(guān)于bitmap的一些基本概念:
DIB:設(shè)備無關(guān)位圖。
DDB:設(shè)備相關(guān)位圖。
掃描順序scan order:bottom-up DIB和top-down DIB。
DDB總是top-down的.
2. 關(guān)于drawing surface:
可以理解為繪制圖象的區(qū)域,程序調(diào)用CreateDC或GetDC后,系統(tǒng)在返回DC句柄(handle)前先將一個(gè)drawing surface(繪制區(qū)域)選入DC,再返回DC句柄,后面進(jìn)行的繪制操作將限制在這個(gè)drawing surface(繪制區(qū)域)中。例如:如果使用CreateDC創(chuàng)建一個(gè)關(guān)于顯示器的DC(device content),那么繪制區(qū)域?yàn)轱@示器的整個(gè)屏幕,而如果使用GetDC獲取一個(gè)對話框窗口或客戶區(qū)的DC,那么繪制區(qū)域則為對話框窗口或客戶區(qū)。
To creates a DC, call the CreateDC function; to retrieve a DC, call the GetDCfunction. Before returning a handle that identifies that DC, the system selects a drawing surface into the DC. If the application called the CreateDC function to create a device context for a VGA display, the dimensions of this drawing surface are 640-by-480 pixels. If the application called the GetDC function, the dimensions reflect the size of the client area.
3.關(guān)于內(nèi)存設(shè)備內(nèi)容。
因?yàn)榕c某個(gè)具體的device content相關(guān),所以又叫作compatible device context.可以象操作其它device content一樣操作它,效果相同,唯一的區(qū)別是它不會顯示出來,必須用BitBlt之類的函數(shù)將它的內(nèi)容COPY(復(fù)制)到它相關(guān)的具體device content中才能顯示出來。它的主要目的是用來暫存圖象數(shù)據(jù)。
It is an array of bits in memory that an application can use temporarily to store the color data for bitmaps created on a normal drawing surface. Because the bitmap is compatible with the device, a memory DC is also sometimes referred to as a compatibledevice context.
使用CreateCompatibleDC創(chuàng)建Memory Device Contexts。
4.關(guān)于bitmap的創(chuàng)建。
一些關(guān)于bitmap創(chuàng)建的函數(shù):
CreateBitmap, CreateBitmapIndirect兩個(gè)基本相同,都創(chuàng)建DDB(device-
dependent bitmap),只能使用selectobject將創(chuàng)建的bitmap選入相關(guān)的(具有相同格式)device。
CreateCompatibleBitmap和CreateDIBitmap也都創(chuàng)建DDB,但前者指定了一個(gè)相關(guān)的device,而后者是從一個(gè)DIB創(chuàng)建DDB.
CreateDIBSection才真正創(chuàng)建DIB.
Performs a bit-block transfer. | |
Creates a bitmap. | |
Creates a bitmap. | |
Creates a bitmap compatible with a device. | |
Creates a device-dependent bitmap (DDB) from a DIB. | |
Creates a DIB that applications can write to directly. | |
Loads a bitmap from a module's executable file. | |
Copies a bitmap and stretches or compresses it. | |
Copies the color data in a DIB. |
其中BitBlt和StretchBlt和StretchDIBvits用來真正顯示bitmap,而
LoadBitmap則用來加載資源文件中的bitmap。
5.關(guān)于bitmap的存儲。
The established bitmap file format consists of a BITMAPFILEHEADER structure followed by a BITMAPINFOHEADER, BITMAPV4HEADER, or BITMAPV5HEADER structure. An array ofRGBQUAD structures (also called a color table) follows the bitmap information header structure. The color table is followed by a second array of indexes into the color table (the actual bitmap data).
The bitmap file format is shown in the following illustration.
圖一
可以看出bitmap由BITMAPFILEHEADER+BITMAPINFOHEADER(或其它bitmap header結(jié)構(gòu))+顏色表+指向顏色表的實(shí)際圖象數(shù)據(jù)組成。
下面主要來看一看bitmap的四個(gè)組成部分:
一、關(guān)于BITMAPFILEHEADER結(jié)構(gòu):
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;
Members
bfType
指定文件類型,必須是0x424D,即字符串“BM”,也就是說所有.bmp文件的頭兩個(gè)字節(jié)都是“BM”。
Specifies the file type, must be BM.
bfSize
指定文件大小,包括這14個(gè)字節(jié)。單位:bytes。
Specifies the size, in bytes, of the bitmap file.
bfReserved1
Reserved; must be zero.
bfReserved2
Reserved; must be zero.
bfOffBits
為從文件頭到實(shí)際的位圖數(shù)據(jù)的偏移字節(jié)數(shù),即圖一中前三個(gè)部分的長度之和。
Specifies the offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits.
二、關(guān)于BITMAPINFOHEADER結(jié)構(gòu):
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, *PBITMAPINFOHEADER;
Members
biSize
此結(jié)構(gòu)(BITMAPINFOHEADER)的大小,單位:byte。
Specifies the number of bytes required by the structure.
biWidth
bitmap的寬,單位:pixel。
Specifies the width of the bitmap, in pixels.
biHeight
bitmap的高,單位:pixel。
Specifies the height of the bitmap, in pixels.
biPlanes
目標(biāo)設(shè)備(即bitmap最終繪制的設(shè)備)平面的數(shù)目。一般為1,例如顯示器和打印機(jī)都只有一個(gè)顯示平面,對話框窗口和客戶區(qū)也只有一個(gè)面,因此biPlanes的值必須設(shè)為1.
Specifies the number of planes for the target device. This value must be set to 1.
biBitCount
表示一個(gè)像素的顏色需要用到的位數(shù),取決于bitmap的顏色數(shù)目(biBitCount 和bitmap顏色數(shù)目的關(guān)系:2^ biBitCount等于bitmap的顏色數(shù)目,很簡單,因?yàn)槎M(jìn)制1 bit(位)只能表示2^1即兩個(gè)值,2位可以表示2^2個(gè)值……)。例如,如果是黑白二色圖,則表示一個(gè)像素的顏色只需要1位,即biBitCount為1,如果bitmap是16色的話,則每一個(gè)像素需要4位才能表示其顏色。
常用的值為1(黑白二色圖), 4(16色圖), 8(256色), 24(真彩色圖)
單位:bits。
biCompression
指定位圖是否壓縮,有效的值為BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS(都是一些Windows定義好的常量)。要說明的是,Windows位圖可以采用RLE4和RLE8的壓縮格式,但用的不多。一般bitmap為第一種不壓縮的情況,即biCompression為BI_RGB的情況。
biSizeImage
指定實(shí)際的位圖數(shù)據(jù)占用的字節(jié)數(shù),如果biCompression為BI_RGB,則該項(xiàng)可能為零。因?yàn)锽I_RGB為不壓縮,所以biSizeImage其實(shí)也可以從以下的公式中計(jì)算出來:
biSizeImage=biWidth’ × biHeight
要注意的是:上述公式中的biWidth’必須是4的整倍數(shù)(所以不是biWidth,而是biWidth’,表示大于或等于biWidth的,最接近4的整倍數(shù)。舉個(gè)例子,如果biWidth=240,則biWidth’=240;如果biWidth=241,biWidth’=244)。如果biCompression為壓縮值,則上面的等式不成立。
單位:bytes。
biXPelsPerMeter
指定目標(biāo)設(shè)備的水平分辨率,單位是每米的象素個(gè)數(shù)。
biYPelsPerMeter
指定目標(biāo)設(shè)備的垂直分辨率,單位同上。
biClrUsed
指定本圖象實(shí)際用到的顏色數(shù),即顏色表(或調(diào)色板)中顏色的數(shù)目。如果該值為零,則用到的顏色數(shù)為2biBitCount。
biClrImportant
指定本圖象中重要的顏色數(shù),如果該值為零,則認(rèn)為所有的顏色都是重要的。
三、關(guān)于顏色表(即調(diào)色板palette)
The RGBQUAD structure describes a color consisting of relative intensities of red, green, and blue.
RGBQUAD結(jié)構(gòu)用來表示顏色,bitmap結(jié)構(gòu)的第三部分是一個(gè)RGBQUAD數(shù)組,數(shù)組中元素的數(shù)目就是bitmap的顏色數(shù),也就是說數(shù)組中每一個(gè)元素(每一個(gè)RGBQUAD)代表一種顏色。RGBQUAD結(jié)構(gòu)的大小為4字節(jié),所以bitmap第三部分調(diào)色板的大小等于bitmap的顏色數(shù)目乘以4.舉個(gè)例子:如果是黑白二色圖,則
Bitmap的調(diào)色板大小為8字節(jié);如果是16色圖,則bitmap的調(diào)色板大小為64字節(jié)。
typedef struct tagRGBQUAD {
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
} RGBQUAD;
Members
rgbBlue
此顏色的藍(lán)色分量,取值范圍0~255,剛好可以用一個(gè)BYTE表示,因此類型為BYTE.
Specifies the intensity of blue in the color.
rgbGreen
此顏色的綠色分量,同上。
Specifies the intensity of green in the color.
rgbRed
此顏色的紅色分量,同上。
Specifies the intensity of red in the color.
rgbReserved
Reserved; must be zero.
注意:真彩色圖(24位色圖)沒有第三部分,也就是說沒有調(diào)色板。
四、關(guān)于實(shí)際位圖數(shù)據(jù)(color-index array)部分:
The color-index array associates a color, in the form of an index to an RGBQUADstructure, with each pixel in a bitmap. Thus, the number of bits in the color-index array equals the number of pixels times the number of bits needed to index theRGBQUAD structures. For example, an 8x8 black-and-white bitmap has a color-index array of 8 * 8 * 1 = 64 bits, because one bit is needed to index two colors. The Redbrick.bmp, mentioned in About Bitmaps, is a 32x32 bitmap with 16 colors; its color-index array is 32 * 32 * 4 = 4096 bits because four bits index 16 colors.
位圖中的每一個(gè)像素都是一個(gè)指向顏色表某一項(xiàng)的索引值,即實(shí)際的位圖數(shù)據(jù)。顏色表即RGBQUAD數(shù)組中不同的項(xiàng)(或元素)代表不同的顏色,因此不同顏色的像素指向顏色表中不同的項(xiàng),相同顏色的像素指向指向的項(xiàng)是相同的。
這一部分(即實(shí)際位圖數(shù)據(jù))的大小等于像素的數(shù)目乘以表示bitmap所有顏色(即顏色表中顏色的數(shù)目)所需要的位數(shù)(bits)。例如:一個(gè)32×32的bitmap,如果調(diào)色板中的顏色數(shù)為16,即16色圖,因?yàn)楸硎?6色需要4bits,那么該位圖的實(shí)際數(shù)據(jù)大小=32×32×4 = 4096 bits = 512 bytes。
思考:
位圖結(jié)構(gòu)為什么要定義成這四個(gè)部分?這樣有什么好處?BITMAPFILEHEADER和
BITMAPINFOHEADER各定義了bitmap的哪些方面?為什么要引入調(diào)色板?
下面的內(nèi)容摘錄自《數(shù)字圖象處理編程入門》
我們知道,普通的顯示器屏幕是由許許多多點(diǎn)構(gòu)成的,我們稱之為象素。顯示時(shí)采用掃描的方法:電子槍每次從左到右掃描一行,為每個(gè)象素著色,然后從上到下這樣掃描若干行,就掃過了一屏。為了防止閃爍,每秒要重復(fù)上述過程幾十次。例如我們常說的屏幕分辨率為640×480,刷新頻率為70Hz,意思是說每行要掃描640個(gè)象素,一共有480行,每秒重復(fù)掃描屏幕70次。
我們稱這種顯示器為位映象設(shè)備。所謂位映象,就是指一個(gè)二維的象素矩陣,而位圖就是采用位映象方法顯示和存儲的圖象。舉個(gè)例子,圖1.1是一幅普通的黑白位圖,圖1.2是被放大后的圖,圖中每個(gè)方格代表了一個(gè)象素。我們可以看到:整個(gè)骷髏就是由這樣一些黑點(diǎn)和白點(diǎn)組成的。
那么,彩色圖是怎么回事呢?
我們先來說說三元色RGB概念。
我們知道,自然界中的所有顏色都可以由紅、綠、藍(lán)(R,G,B)組合而成。有的顏色含有紅色成分多一些,如深紅;有的含有紅色成分少一些,如淺紅。針對含有紅色成分的多少,可以分成0到255共256個(gè)等級,0級表示不含紅色成分;255級表示含有100%的紅色成分。同樣,綠色和藍(lán)色也被分成256級。這種分級概念稱為量化。
這樣,根據(jù)紅、綠、藍(lán)各種不同的組合我們就能表示出256×256×256,約1600萬種顏色。這么多顏色對于我們?nèi)搜蹃碚f已經(jīng)足夠豐富了。
表1.1 常見顏色的RGB組合值
顏色 | R | G | B |
紅 | 255 | 0 | 0 |
藍(lán) | 0 | 255 | 0 |
綠 | 0 | 0 | 255 |
黃 | 255 | 255 | 0 |
紫 | 255 | 0 | 255 |
青 | 0 | 255 | 255 |
白 | 255 | 255 | 255 |
黑 | 0 | 0 | 0 |
灰 | 128 | 128 | 128 |
你大概已經(jīng)明白了,當(dāng)一幅圖中每個(gè)象素賦予不同的RGB值時(shí),能呈現(xiàn)出五彩繽紛的顏色了,這樣就形成了彩色圖。的確是這樣的,但實(shí)際上的做法還有些差別。
讓我們來看看下面的例子。
有一個(gè)長寬各為200個(gè)象素,顏色數(shù)為16色的彩色圖,每一個(gè)象素都用R、G、B三個(gè)分量表示。因?yàn)槊總€(gè)分量有256個(gè)級別,要用8位(bit),即一個(gè)字節(jié)(byte)來表示,所以每個(gè)象素需要用3個(gè)字節(jié)。整個(gè)圖象要用200×200×3,約120k字節(jié),可不是一個(gè)小數(shù)目呀!如果我們用下面的方法,就能省的多。
因?yàn)槭且粋€(gè)16色圖,也就是說這幅圖中最多只有16種顏色,我們可以用一個(gè)表:表中的每一行記錄一種顏色的R、G、B值。這樣當(dāng)我們表示一個(gè)象素的顏色時(shí),只需要指出該顏色是在第幾行,即該顏色在表中的索引值。舉個(gè)例子,如果表的第0行為255,0,0(紅色),那么當(dāng)某個(gè)象素為紅色時(shí),只需要標(biāo)明0即可。
讓我們再來計(jì)算一下:16種狀態(tài)可以用4位(bit)表示,所以一個(gè)象素要用半個(gè)字節(jié)。整個(gè)圖象要用200×200×0.5,約20k字節(jié),再加上表占用的字節(jié)為3×16=48字節(jié).整個(gè)占用的字節(jié)數(shù)約為前面的1/6,省很多吧?
這張R、G、B的表,就是我們常說的調(diào)色板(Palette),另一種叫法是顏色查找表LUT(Look Up Table),似乎更確切一些。Windows位圖中便用到了調(diào)色板技術(shù)。其實(shí)不光是Windows位圖,許多圖象文件格式如pcx、tif、gif等都用到了。所以很好地掌握調(diào)色板的概念是十分有用的。
有一種圖,它的顏色數(shù)高達(dá)256×256×256種,也就是說包含我們上述提到的R、G、B顏色表示方法中所有的顏色,這種圖叫做真彩色圖(true color)。真彩色圖并不是說一幅圖包含了所有的顏色,而是說它具有顯示所有顏色的能力,即最多可以包含所有的顏色。表示真彩色圖時(shí),每個(gè)象素直接用R、G、B三個(gè)分量字節(jié)表示,而不采用調(diào)色板技術(shù)。原因很明顯:如果用調(diào)色板,表示一個(gè)象素也要用24位,這是因?yàn)槊糠N顏色的索引要用24位(因?yàn)榭偣灿?span style="FONT-FAMILY: 'Times New Roman'">224種顏色,即調(diào)色板有224行),和直接用R,G,B三個(gè)分量表示用的字節(jié)數(shù)一樣,不但沒有任何便宜,還要加上一個(gè)256×256×256×3個(gè)字節(jié)的大調(diào)色板。所以真彩色圖直接用R、G、B三個(gè)分量表示,它又叫做24位色圖。
聯(lián)系客服