在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比较特殊,暂不讨论)
我们从HWND获得当前DC,通过选进不同的属性来调整DC当前属性项,这样显示操作时就会得到对应效果。
2.Windows显示原理
在继续往下面讲设备描述表和位图前,我想先谈谈Windows的显示原理,说是Windows显示原理,其实所有的操作系统大同小异。
1.显示过程
一般说显示原理都讲操作系统向显卡传递数据,显卡定时将数据刷新到监视器上,将这一过程细化如下图
那么整个过程细化描述如下:
[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