在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

Windows 中GDI、设备描述表和位图相关推荐

  1. K8s(Kubernetes), docker中的registry是什么意思?和windows中的注册表registry有什么区别?

    相信很多初学者会对K8s(Kubernetes)中的registry这个概念感到很困惑,因为翻译成中文实在是不好翻译,直译"注册"就让人觉得非常费解.网上对于这方面的中文资料也很少 ...

  2. 如何通过使用 64 位版本 Windows 查看系统注册表 WOW6432Node

    64 位版本 Windows 中的注册表分为 32 位注册表项和 64 位注册表项.许多 32 位注册表项与其相应的 64 位注册表项同名,反之亦然. 64 位版本 Windows 包含的默认 64 ...

  3. 在 Windows 中启用自动登录功能

    在 Windows 中启用自动登录功能 本文介绍了如何通过将密码和其他相关信息存储在注册表数据库中以配置 Windows 自动执行登录过程. 通过使用此功能,其他用户可以启动您的计算机并使用您建立的帐 ...

  4. Windows编程设备描述表的概念和在客户区绘制、在窗口标题栏绘制、在桌面绘制图解

    设备描述表 设备描述表是一个定义一组图形对象及其属性.影响输出的图形方式(数据)结构.windows提供设备描述表,用于应用程序和物理设备之间进行交互,从而提供了应用程序设计的平台无关性.设备描述表又 ...

  5. MFC中设备描述表dc的使用

    1 以下代码我是在View类中实现的: 2 /** 利用平台SDK实现画线功能 3 // 首先获得窗口的设备描述表 4 HDC hdc; 5 hdc = ::GetDC( m_hWnd ); //调用 ...

  6. linux应用程序注册表,如何打开 Linux 中 Windows 程序的注册表编辑器

    在我们借助CrossOver这款兼容软件在Linux操作系统中运行Windows应用程序的过程中,有的时候我们可能会遇到有关要求,为Windows应用程序设置注册表项的疑难解答问题的提示,指南或说明. ...

  7. Windows 输入法在注册表中的管理

    Windows 输入法在注册表中的管理 查看语言栏的输入法 法一 法二 查看默认输入法 找到默认输入法的 CLSID 根据 CLSID 查找对应的输入法 WINDOWS下输入法中英文切换 切换输入法半 ...

  8. WINDOWS中关于内存管理的注册表优化

    WINDOWS中关于内存管理的注册表优化 [HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Session Manager/Memory Man ...

  9. C 怎么处理windows路径_在Windows中使用msix打包工具监视注册表和文件

    以下内容不涉及任何专业知识,所有人都可以看懂. 此方法只适用于Windows10及更高版本 1.目的 有时候,我们需要找到知道某一时间段内某个应用程序对系统做了哪些修改,例如: 1.1.Windows ...

最新文章

  1. Redis 高级特性(3)—— 持久化及数据恢复
  2. ARM 寄存器 和 工作模式了解
  3. tf.keras.losses.categorical_hinge 分类铰链 损失函数 示例
  4. Dumpzilla工具第615行bug的解决办法
  5. 〖Java〗Eclispe安装和使用viplugin
  6. Zookeeper知识学习
  7. unity3d中画线有几种方式_Spring RestTemplate中几种常见的请求方式
  8. [云炬创业基础笔记]第十一章创业计划书测试8
  9. GetModuleHandle,AfxGetInstanceHandle使用区别
  10. Easyui+Spring+Mybatis完整示例(前台)
  11. 兼容pc端和移动端的轮播图插件 swiper.js
  12. BP神经网络原理分析及c++代码实现(上)
  13. 谷歌如何捕获街景中的门牌号码
  14. 扩展欧几里得算法推导
  15. 计算机试图启动宏,打开电子表格时,将提示禁用或启用宏的解决方案
  16. 【WiFi】WiFi安全类型
  17. 用一个开关,控制LEP灯的亮和灭
  18. 《Wireshark数据包分析实战》读书笔记
  19. Glide加载相同URL时由于缓存无法更新图片的问题
  20. 服务器系统进不了系统错误代码,重启服务器进入点晴OA的Email模块时提示子系统密码错误,错误代码2027:800403e9,如何解决?...

热门文章

  1. 计算机辅助翻译论文的应用环境,计算机辅助翻译(CAT)技术在现代翻译中的应用探析.pdf...
  2. 质量可靠的软件安全测试,漏洞盒子 | 互联网安全测试众测平台
  3. WiFi广告软件实现微信扫一扫看广告有效加粉方法
  4. XSS攻击与CSRF攻击
  5. 阴阳师游戏的特色系统有哪些?
  6. (Inside Out) Web地图坐标系——TDT的神奇
  7. Udesk即时通讯(IM)网页插件入门
  8. VC++上机例题——画椭圆(图形方法总结)
  9. VMware Tools未更新导致vRA7自动化部署Windows虚拟机失败
  10. for循环 | range 对象