天天看點

Windows 中GDI、裝置描述表和位圖

在Windows中,所有的圖形和圖像顯示操作都是通過GDI(Graphic Device Interface)子產品完成,,而GDI的顯示都是由裝置描述表(Context Device,簡稱DC)來完成的,裝置描述表同顯示驅動程式打交道,顯示驅動程式再同顯示硬體打交道,最終得到指定的顯示效果。基本所有的書提到裝置描述表時都告訴我們把裝置表看成一個虛拟對象,所有顯示操作同它打交道即可。誠然,在寫程式的時候這樣是明智的,然而,當遇到具體的顯示細節問題時(如調色闆的使用、DIB圖像的顯示等),去了解裝置描述表的結構是必然的,而裝置描述表結構的核心是位圖。相信看完這篇部落格你可以一解在GDI程式設計中的許多疑惑。

1.GDI的構成

GDI的幾個基本對象是畫筆(HPEN),畫刷(HBRUSH),字型(HFONT),位圖(HBITMAP),調色闆(HPALETTE),元檔案(HMETAFILE)。聯系這些基本對象和GDI顯示輸出的是裝置描述表(HDC)。

通常我們使用GDI的格式類似如下:

//擷取裝置描述表
hdc = GetDC(hwnd);

//更改裝置描述表項
SelectObject(hdc, GetStockObject(GRAY_BRUSH));

//通過裝置描述表執行相應顯示操作
MoveToEx(hdc, 0, 0, NULL);
LineTo(hdc, 10, 10);

//恢複裝置秒速表項
SelectObject(hdc, GetStockObject(WHITE_BRUSH));

//取消獲得裝置描述表
ReleaseDC(hwnd, hdc);
           

前面我們已經說過,實際上USER子產品根本上也是由GDI來完成的,可以猜想整個GDI的句柄表結構(看做結構體和成員關系)如下:(HMETAFILE比較特殊,暫不讨論)

Windows 中GDI、裝置描述表和位圖

我們從HWND獲得目前DC,通過選進不同的屬性來調整DC目前屬性項,這樣顯示操作時就會得到對應效果。

2.Windows顯示原理

在繼續往下面講裝置描述表和位圖前,我想先談談Windows的顯示原理,說是Windows顯示原理,其實所有的作業系統大同小異。

1.顯示過程

一般說顯示原理都講作業系統向顯示卡傳遞資料,顯示卡定時将資料重新整理到螢幕上,将這一過程細化如下圖

Windows 中GDI、裝置描述表和位圖

那麼整個過程細化描述如下: [1].使用者顯示操作通過裝置描述表(DC)傳遞至相應的顯示裝置驅動程式,再由驅動程式 和顯示卡打交道來設定顯示卡資料區(顯存)對應像素點的資料,對于深度BitCount=8位的顯示卡需要設定調色闆的調色闆表(這一個等下要詳細讨論) [2].顯示卡定時讀取資料區資料,對于深度BitCount<=8位的資料要查調色闆表成相應的RGB值傳遞給螢幕。 [3].螢幕将得到的一個RGB值分成RGB三色值,再通過這三個值設定相關實體信号(如電壓),實體信号作用得到R、G、B三個分色,三個分色疊加即可得到這個RGB對應的像素點的顯示效果。

2.顯示卡發展史

在談到Windows顯示原理的時候不得不提顯示卡的發展史,盡管現在看來一些特性已經基本上用不到了,但是在Windows顯示曆史上它們卻起到了非常重要的作用,這裡參考Petzold Windows Programming中相關内容講解。

單色顯示卡

Windows1.0中使用單色圖形卡。 對應上節中的顯示卡參數為 深度BitCount:1 位平面Planes:1 假設最大支援480*320分辨率,那麼資料區應該是480*320的矩陣存儲器單元,每個存儲器單元對應的值為1或0,即單個像素值需要的存儲器單元大小為1bit 單色顯示卡沒有調色闆,顯示的時候1直接傳遞給螢幕RGB(255,255,255),0傳遞RGB(0,0,0)(當然,這裡隻是理論上的,具體細節就不再深入了)

16色顯示卡

随着硬體的發展,針對單色顯示卡人們做了改進,使用4個位面,每個位面的深度為1,如上節中顯示卡示意圖,即 對應上節中的顯示卡參數為 深度BitCount:1 位平面Planes:4 這樣理論上就可以最大支援16種顔色。假設我們将4個位面的對應位置資料寫成如下形式:位面1-位面2-位面3-位面4,這樣每個對應的像素點的值範圍為0-0-0-0~1-1-1-1 但是現在的問題來了,怎麼知道0-0-0-1對應的RGB顔色是什麼顔色呢? 于是人們發明了調色闆,每次顯示的時候讀取0-0-0-1然後查表得到對應的RGB值再傳遞給螢幕。理論上調色闆表對應16個調色闆項,但人們又想既然已經有了多個調色闆項,幹脆将調色闆表做成64個,讓人們可以選擇其中的16色來對應。Windows使用最簡單的方式即選擇固定的16個對應顔色來顯示。

256色顯示卡

Windows 98後相當一段時間内256色顯示卡比較流行,直到現在很多程式還要求運作在256色相容模式下。這時候硬體存儲技術發展越來越快,短暫出現的擴充位面來增強顔色顯示的方法因為不友善很快被抛棄了。在256色顯示卡中,每個像素用8bit即1Byte來存儲,即顯示卡參數為 深度BitCount:8 位平面Planes:1 這樣每個像素點的值為0x00~0xFF,即256中顔色。同樣為了确認0-255中每個數字代表什麼RGB色,采用了256色調色闆。然而,人們對于256色顯示效果依然不滿意,這時候的Windows不再是簡單的使用調色闆了,這樣就說道了我們上面說到的問題,可以通過裝置描述表動态調整調色闆表項的RGB值,即采用這種迂回的方式在不同顯示需求下達到最好的顯示效果。 例如:假設原來像素值點值3-查表對應RGB(255,0,128),通過調整調色闆表将3對應的調色闆項改為RGB(255,255,0),這樣每次值為3的像素點顯示即為RGB(255,255,0)。

16位顯示卡

随着硬體的發展,顯存越來越大,人們對顔色的要求也越來越高,256色顯然不足夠了。這時候,16位顯示卡被推出,這裡的16位指的是顔色深度而不是通常意義上上的顯示卡帶寬。即顯示卡參數為 深度BitCount:16 位平面Planes:1 16位顯示卡和256色顯示卡類似,隻是每個像素點值占位16bit即2Byte,這時候人們覺得已經可以把RGB值直接存儲在像素點資料區了,即R、G、B分值占位5bit,多出的一位可以不用或給綠色通道。這樣按照R-G-B占位的順序(按照綠色占6bit算),每個像素點資料範圍為00000-000000-00000~11111-111111-11111。當然為了能夠讓RGB每個通道完全表示0-255,需要每個通道間隔取值,例如R通道可能取得值為0、8、16、24......,為32級灰階。16位顯示卡可表示32768或65536(綠色6bit)中顔色,已經滿足人們的基本需求了,現在的顯示卡一般都支援16位模式。

24位和32位顯示卡

現在的顯示卡位數基本上都是24位或32位。顯示卡參數為 深度BitCount:24或32 位平面Planes:1 24位顯示卡對應的像素點很簡單:RGB三個通道各占8位,即像素點範圍為0x00-0x00-0x00~0xFF-0xFF-0xFF,可顯示16777216種顔色。32位顯示卡在24位顯示卡基礎上加入了Alpha通道,原理是一樣的。

可以看出:整個Windows的顯示技術随着顯示卡的發展的做了很多改變,時至今日,很多顯示選項(如調色闆和位面)之是以存在更多的是為了保證程式的相容性。

3.螢幕的超前發展

提到了顯示卡的發展史,不得不提一下螢幕,這裡把它直接當做顯示器好了。顯示器有個參數叫顔色分辨率,如18位,和16位顯示卡原理一樣,18位也是采用每個通道6位來區分顔色,如R通道取值為0、4、8、12、16...,當從顯示卡傳遞過來的R資料為9時取最近值8,即顯示和指定效果有差别。當然,這裡隻是一個假設,事實上螢幕的發展速度遠遠超過顯示卡,在Windows 1.0還在采用單色顯示卡的時候,螢幕就已經支援多種彩色了。現在的顯示器基本上都是24位和32位,剛才提到的這個問題是在你使用新的顯示卡和老式顯示器得不到理想的顯示效果時應該考慮的問題。

3.裝置描述表和位圖

關于裝置描述表的定義,Petzold給出的定義是“裝置描述表指的是某個圖形輸出裝置(例如視訊顯示器或列印機),及其裝置驅動程式”。這個定義比較晦澀。事實上裝置描述表的誕生是為了相容各種顯示裝置(顯示器、列印機、投影儀等等)和隔離程式員與硬體,Windows中所有 的顯示操作都是同裝置描述表打交道。 嚴格來講,裝置描述表應該專指記憶體中的HDC句柄對應的DC結構體。 裝置描述表結構的核心是位圖。為什麼這樣說呢?我們說了裝置描述表時為了相容各種顯示裝置,這樣對不同的顯示器,裝置描述表的結構是不一樣的,結合記憶體裝置描述表結構,我們可以可以知道記憶體裝置描述表中包含的位圖結構對應于實際硬體顯示卡的結構

如顯示卡支援分辨率為:1024*768,深度為32位,位面數為1 那麼對應的裝置描述表結構中的位圖結構大小為:1024*768,深度為32位,位面數為1,每個像素點資料對應于顯示卡中資料區的像素點。這樣在顯示操作時實際上是操作DC對應的位圖結構,位圖結構在對應于相關顯示卡資料區,達到了屏蔽硬體差異性的效果。當我們使用SDK函數Bitblt最能感受到這一點。 對于256色顯示,Windows還支援調色闆操作,這個DC下的調色闆對應于實際顯示卡的調色闆,原理是一樣的。 至于DC下的HPEN、HBRUSH和HFONT隻是軟體是為顯示操作而建構的輔助工具。

關于GDI還有一點要注意的是最近顔色顯示問題,在DC中操作一般我們使用RGB指定顔色,但是我們知道在BitCount<=16位顯示卡下我們無法顯示所有的RGB值,對于256色顯示卡會查找調色闆得到最近顔色的調色闆索引作為像素點值,對于16位顯示卡會直接計算最近支援的RGB值作為像素點值。Windows SDK提供GetNearestColor函數手動計算最近顔色。在256色使用調色闆的情況下,可以直接指定顔色為調色闆索引号加快速度,略去計算最近顔色過程。

4.總結

好了,整個Windows 中GDI、裝置描述表和位圖大體系算是講完了,總的來說就是GDI程式設計時把裝置描述表對應到顯示卡結構上,以位圖為核心來思考細節問題。當然,在現在的24位和32位顯示卡下,很多問題如調色闆、位面都不用考慮了,但是了解這些問題對于GDI程式設計和DIB位圖的處理都有幫助。

原創,轉載請注明來自 http://blog.csdn.net/wenzhou1219

繼續閱讀