第七课∶位图
一、概述
在Windows中每屏是一个图形图像,灵巧的Windows制作系统,面对庞大的图形编程任务,建立了为绘画多彩的边界、按钮、图标、字体的函数库。当然啦,通过Windows API,这些函数都是可调用的。所谓Windows显示屏幕以及数量众多的打印机其实都是属于“光栅设备”。在光栅设备中,一幅图象由多条扫描线以及能访问的单独像素构成。Windows也支持非光栅设备,比如绘图仪等,本人对此一无经验,无从谈起,想来也差不到哪儿去。以下只以显示器为重点展开讨论。
计算机视频系统的核心是内存。该内存包含代表着显示图案的数据,而这些图案显示在监视器(显示器)上。每次鼠标移动时,内存中的少量数据发生变化。然后你会看到鼠标指针在屏幕上移动。每次以及每一个图形操作都会影响视频内存,因为GDI执行计算并以相应方式更改视频内存。计算机中还有一个存放图象数据的内存,叫做位图内存。位图内存与视频内存的重要的一个区别是∶位图内存看不到,而视频内存则能够看到。也就是说放在位图内存的图象数据并不反映在屏幕上,而视频内存中存放的图象信息则反映在监视器上。如果把驻留在位图内存的数据移动到视频内存中,那么图象将显示在监视器上。以一个桌面图标为例,图标从磁盘加载到内存中(位图内存)中,然后内存被移到视频内存中的适当地址上,这样当视频内存通过视频硬件被显示到屏幕上时,图标成为可见的。
从图象的种类来讲,Windows中存在两种位图,一种叫与设备有关位图(或叫设备相关位图),另一种叫与设备无关位(或叫设备无关位图,或DIB)。除非特别声明,W indows中的位图都是与设备有关的位图。有些朋友一说位图,就可能想到BMP图象,但它是属于与设备无关的位图。在编程的领域我们常常说位图,一般并不是指BMP图象,而是指对他们来说也是想象中存在的那个叫与设备有关的位图。另一个区别与设备有关位图和与设备无关位图的重要依据是,判断该位图是否具有句柄。具有句柄的位图便是与设备有关的位图,因为它是GDI对象之一。常见的BMP图象则属于与设备无关的位图。我们一般不叫它位图,而是叫做“BMP图象”或者叫做“DIB”,它是一种数据的组织方式,并非GDI绘图对象。
可以把与设备无关位图理解为对与设备有关位图数据的一种标准格式的数据保存方式。比如我们平常看到的附加名为BMP的文件。这种位图文件会在文件头上放置文件的组织信息,形式上讲和一些数据库文件的文件头起着同样的作用━━描述文件的结构。文件头后面紧跟着的是图象的颜色数据。由于这种机制的存在,使得与设备无关的位图可以在各种设备之间进行读写。
与设备无关的位图只有一种格式,而与设备有关的位图则可能...大概有多少种设备就有多少种格式吧?鬼才知道!幸运的是您根本没有必要了解它的格式,只需简单理解为保存图象数据的内存块就可以了。就好像您跟本不用了解我长得什么模样,也照样能和我打交道一样。
PC的视频系统显示一个像素的矩阵(整齐排列的小光点)。在一个基于字符的环境中,视频系统包含一套"硬件编程"的形状,代表标准字符的位置及各种画图字符(直线、角线、实线等等)和几个符号(笑脸、钻石、铲等)。通过发送给系统一个ASCII码或ANSI字符码来显示一个字符。而在Windows这样一个图形显示系统中,计算机及其软件定义出现在屏幕上的图形形状。这些形状是用位图来代表的。用这种方法的最主要的优点是图象和文本能以不同的大小、字体、方式来显示。那么,准确地说,什么是位图呢?它们是数据元素的集合,这些数据元素决定在每个屏幕位置上显示什么样的颜色。在单色的(黑和白)图形图像中,每位代表一个屏幕像素,0对应黑(没有颜色),1对应白(显示色)。不久您就会看到,位图能描述彩色图像。每个像素的位数决定能在单个位图中出现的不同色彩的数目。除了每个像素一位的单色视频,还有其他三种∶每个像素4位产生16种颜色,8位产生256种颜色,24位产生16'777'216种颜色(补充:我已经亲眼看到了32位显卡)。如下表所示∶
Windows支持的彩色
每个像素的位数 颜色总数 典型设备
1 2 单色图形
4 16 标准备VGA
8 256 256色VGA
16 32'768或65'536 32K或64K色SVGA
24 16'777'216 24位真彩色设
计算机显示系统的性能决定Windows对彩色图象的处理。现在常看到的显示器是SVGA(AGP也出来了,我的就是,但资料少无从谈起)。理论上讲,SVGA系统能显示惊人的含有16'777'216种颜色数组。把能够显示16'000'000种颜色范围的系统通常称为真彩色(true color)。那么"真彩色"的真实意思是什么呢?它源于对是否一个彩色显示器能显示无限大范围的颜色的想象,图象将看起来完全逼“真”。真彩色的显示用24位来决定每个像素的颜色。24位被分成三组,每组8位,来表示红、绿、蓝三种颜色。(参考∶自然界的颜色是通过红、绿、蓝(RGB)三种颜色来组合而成的。叫做三元色。)
二、与设备无关位图(DIB)
所谓DIB是指与设备无关的位图。DIB并不是Windows的对象,它没有自己的句柄,实际上是一种数据文件。和很多数据文件相同,DIB位图文件的开头部分有它内在的数据结构描述部分。不少书做了一些示意图来说明这个问题,但我觉得还是亲眼目睹DIB文件的内部更好一些,百闻不如一睹嘛。
现在我们准备要看的BMP文件是一个256色位图,文件名叫Hua.bmp ,这个文件曾在《VB前线》的演示程序第25号中使用过。
首先让我们查看一下文件在磁盘中的大体状况∶
D:/vbplay/vbplay25/>dir
Volume in drive D is PRO
Volume Serial Number is 268F-AB4B
Directory of D:/vbplay/vbplay25
. <DIR> 03-27-99 20:47 .
.. <DIR> 03-27-99 20:47 ..
PLAY25 VBW 111 09-20-99 23:43 play25.vbw
MSSCCPRJ SCC 193 04-07-99 23:52 MSSCCPRJ.SCC
BITMAP CLS 12,711 06-16-99 21:27 Bitmap.cls
MYMEMORY CLS 3,419 04-08-99 2:07 MyMemory.cls PLAY25 VBP 636 06-16-99 21:42 play25.vbp
HUA BMP 96,446 04-04-99 12:06 hua.bmp
PL25_1 FRM 3,865 06-16-99 21:25 pl25_1.frm
7 file(s) 117,381 bytes
2 dir(s) 569,049,088 bytes free
看到了吧?它的大小是96?46个字节。接下来,我们可以用DEBUG的d命令以16进制形式来显示文件的文件头信息。操作如下∶
D:/vbplay/vbplay25/>debug hua.bmp
-d 100 1000
0EAE:0100 42 4D BE 78 01 00 00 00-00 00 36 04 00 00 28 00 BM.x......6...(.
0EAE:0110 00 00 69 01 00 00 06 01-00 00 01 00 08 00 00 00 ..i.............
0EAE:0120 00 00 88 74 01 00 C4 0E-00 00 C4 0E 00 00 00 00 ...t............
0EAE:0130 00 00 00 00 00 00 00 00-00 00 80 80 80 00 00 00 ................
0EAE:0140 80 00 00 80 80 00 00 80-00 00 80 80 00 00 80 00 ................
0EAE:0150 00 00 80 00 80 00 40 80-80 00 40 40 00 00 FF 80 ......@...@@....
0EAE:0160 00 00 80 40 00 00 FF 00-40 00 00 40 80 00 FF FF ...@....@..@....
省略了57行∶50 - 16 -1 = 39(16进制) = 57(10进制)
0EAE:0500 CC 00 AD E8 FD 00 78 AE-D3 00 1F 38 65 00 66 89 ......x....8e.f.
0EAE:0510 F0 00 63 9B C3 00 79 AD-DA 00 08 13 73 00 0A 1C ..c...y.....s...
0EAE:0520 A5 00 BB ED FD 00 83 C1-E5 00 2A 50 74 00 7C B3 ..........*Pt.|.
0EAE:0530 ED 00 56 82 BD 00 B3 66-B3 B3 6C B3 BD 8B C9 C9 ..V....f..l.....
0EAE:0540 BD 50 21 60 6C 6C 44 44-B3 44 6C 86 44 66 44 D9 .P!`llDD.Dl.DfD.
0EAE:0550 44 B3 6C C9 87 7B B9 7B-44 BD 87 60 87 C9 6C AB D.l..{.{D..`..l.
0EAE:0560 60 D6 6C AB AB 2A 88 55-88 7B 7B 7B 7B 3D 3D 3D `.l..*.U.{
{
{
{===
0EAE:0570 C5 3D C5 24 7B 7B 7B 7B-B4 B9 7B B9 B5 C6 3D 7B .=.${
{
{
{..{...={
(以下全部省略)
0EAE:1000 B3 .
-q
注∶若使用D:/vbplay/vbplay25/>debug hua.bmp >> Temp.txt则可以把结果保存到Temp.txt文件,并可加以分析研究。但这样给出命令后什么都看不见。这时,你应当键入d 100 1000这个命令后回车,然后再按q就可以返回到DOS命令行提示符下。这段内容是这样获取的。详细内容,可参考有关DOS命令参考手册。用pctools5.0也可以。
通过上述方式获取的是该位图文件第一个字节开始的若干个字节的16进制形式的文本内容。以下,我们具体分析一下。在分析以前为了在整体上把握DIB文件的结构,有必要先给出其整体情况,如下表格所示∶
DIB文件的组成
三大部分 字节 说明
BITMAPFILEHEADER 14 用红色表示的部分
BITMAPINFO BITMAPINFOHEADER 40 用深绿色表示的部分
RGBQUAD(结构数组) 最小0,最大4×256。(在16位以上的位图中,根本不存在此部分) 用深红色表示的部分
数据部分 大于0(具体大小信息记录在BITMAPINFOHEADER结构中) 用下划线表示的部分
可以看出,DIB的文件头主要由两个部分组成,即BITMAPFILEHEADER和BITMAPINFO,
而BITMAPINFO又分为BITMAPINFOHEADER和RGBQUAD两个小部分。让我们一个一个分析。首先是开头以红色表示的14个字节,如下
42 4D BE 78 01 00 00 00-00 00 36 04 00 00
这是BITMAPFILEHEADER结构部分。BITMAPFILEHEADER结构如表所示∶
BITMAPFILEHEADER结构
结构内各字段 数据类型 说明
bfType Integer 指定文件类型,必须 BM
bfSize Long 指定位图文件大小,以字节为单位
bfReserved1 Integer 保留未用,必须设为0
bfReserved2 Integer 同上
bfOffBits Long 从此结构到位图数据位的字节偏移量
此结构,主要记录了DIB文件大小以及结构有关的信息。在很多情况下,可以计算来获取这些这些信息,所以很多人并不访问这个结构内的数据。不少人说
BITMAPFILEHEADER结构记录着无大用处的信息。其中bfOffBits说明的是从此结构到位图数据位的字节偏移量。通过对此字段的访问,我们可以知道这个位图文件的颜色数据是从哪里开始的,或者可以知道DIB文件头的结构有多长。
m_BMFileHeader.bfType = 42 4D
这是一个Integer整型数据,对DIB文件来说此数据必须是42 4D。那么为什么定为42 4D呢,其实是在ASCII码表中42即十进制的66表示大写B,4D即十进制的77表示M,也就是说字符擝M數囊馐丁?梢远哉飧稣褪莸姆梦世磁卸衔募欠袷荄IB(或BMP)文件。
m_BMFileHeader.bfSize = BE 78 01 00 = &H178BE = 96446个字节
说明文件的总长度。注意,右侧的数据是高字节,即右侧字节的地址比左侧字节的地址值大,所以BE 78 01 00 = &H178BE。在上面,用dir命令观察文件时,我们已经看到文件的长度正是96446个字节。如∶
HUA BMP 96,446 04-04-99 12:06 hua.bmp
m_BMFileHeader.bfReserved1 = 00 00 (系统保留,没有设置数据)
m_BMFileHeader.bfReserved2 = 00 00 (系统保留,没有设置数据)
m_BMFileHeader.bfOffBits = 36 04 00 00 = &H00000436 = 1078 =14 + 40 + 256 * 4
(从文件开始处起,带下划线的数据位的以字节为单位的长度,总共1078个字节。对真彩色图象来说,这个数据经常是36 00 00 00,即54。说明文件头只有BITMAPFILEHEADER(14个字节) + BITMAPINFOHEADER(40个字节)的部分,即没有RGBQUAD部分。为什么没有RGBQUAD部分也可以?稍后你就明白怎么一回事。继续往下看,继续)
与此结构紧连在一起的下一个叫BITMAPINFO的结构,其组成如下表所示∶
BITMAPINFO结构(表二)
结构内各字段 数据类型 说明
bmiHeader BITMAPINFOHEADER 一个 BITMAPINFOHEADER
bmiColors RGBQUAD 一个 RGBQUAD结构组成的数组
从此表中可以看出,结构内部还存在两个结构,即BITMAPINFOHEADER和RGBQUAD。因此,从某种意义上讲,位图文件的文件头结构可以说为三个结构来构成的: BITMAPFILEHEADER 、BITMAPINFOHEADER和RGBQUAD。但,必须认清的是BITMAPINFO结构并不是离开BITMAPINFOHEADER和RGBQUAD这两个结构而独立存在的。BITMAPINFOHEADER结构的长度是固定着的,为40个字节。BITMAPINFOHEADER结构的有关说明,可参考如下表∶
BITMAPINFOHEADER结构(表三)
结构内各字段 数据类型 说明
biSize Long 结构长度(40)
biWidth Long 指定位图的宽度,以像素为单位
biHei