位图资料

原创 2007年09月18日 09:54:00





绪言返回目录


位图在Windows系统平台中是一种很常见的图像格式,如果从保存图像的性能上来讲它不是最好的,JPG、GIF格式都超过它,但是由于它是微软公司制定的标准,并且已嵌入了操作系统,所以它就显得很重要了。以下的内容是我根据VC5.0的联机帮助翻译而来的,有些地方我加入了自己的观点(都已用括号表明),因为我对位图的知识掌握的也不是太深,所以可能有些地方翻译的不是太准确,甚至是错误,如果哪位高手发现了,请不吝赐教。同时,我也希望这份资料能对那些想了解位图的朋友有所帮助,那是我编译这份资料的最大愿望!



关于位图 (About Bitmap)返回目录


位图是能被选入设备描述表(DC)的七种目标之一,其余的六种目标是:笔(pen)、刷(brush)、字体(font)、区域(region)、逻辑调色板(logical palette)、和路径(path)。在微软Win32应用程序界面(API)中,控制面板应用程序就是一种使用位图的程序,当用户为桌面选择壁纸的时候,实质上他选择的就是位图,Windows系统将根据这张位图来绘制桌面。从用户的角度来看,位图只是一个矩形的图像,而在开发者的眼中,位图则是一个结构的集合体。它可能包含以下的一些元素:

* 一个描述图像信息的结构,比如图像的大小(宽、高)、位数组的尺寸、创建这张图片的设备的分辩率,等等。
* 一个逻辑调色板
* 一个位数组,它定义了像素值与逻辑调色板的关系(译者注:如果该图片有逻辑调色板的话,如果没有调色板,位数组中的像素值将直接代表各像素的颜色分量)。

下面的图例可用于说明一个位图的真实位数组内容:

在前面这个范例中,图像是创建于一个VGA的显示器,这种设备使用了一个16色的调色板,而一个16色的调色板至少需要4位的索引值才能表示(2^4),所以,在位图的位数组中,每个像素都是用4位(半个字节)来表示索引值的。
注意:在上面的位图的中,Windows系统映射索引值到像素时是先从底扫描行开始,到顶扫描行结束的(扫描行是图像中水平方向的一个单行的所有像素)。比如,位数组中的第一行(row 0)对应于图像的最底行。这是因为上面这张位图是一张底到上型(bottom-up)的DIB(设备无关)位图,这也是一种很普通的位图。对于顶到下型的DIB以及DDB位图来说,Windows系统映射索引值到像素时则是从顶扫描行开始的。

位图的类型 (Bitmap Types)返回目录

位图一共有两种类型,即:设备相关位图(DDB)和设备无关位图(DIB)。DDB位图在早期的Windows系统(Windows 3.0以前)中是很普遍的,事实上它也是唯一的。然而,随着显示器制造技术的进步,以及显示设备的多样化,DDB位图的一些固有的问题开始浮现出来了。比如,它不能够存储(或者说获取)创建这张图片的原始设备的分辩率,这样,应用程序就不能快速的判断客户机的显示设备是否适合显示这张图片。为了解决这一难题,微软创建了DIB位图格式。

设备无关位图 (Device-Independent Bitmap)

DIB位图包含下列的颜色和尺寸信息:
* 原始设备(即创建图片的设备)的颜色格式。
* 原始设备的分辩率。
* 原始设备的调色板
* 一个位数组,由红、绿、蓝(RGB)三个值代表一个像素。
* 一个数组压缩标志,用于表明数据的压缩方案(如果需要的话)。

以上这些信息保存在BITMAPINFO结构中,该结构由BITMAPINFOHEADER结构和两个或更多个RGBQUAD结构所组成。BITMAPINFOHEADER结构所包含的成员表明了图像的尺寸、原始设备的颜色格式、以及数据压缩方案等信息。RGBQUAD结构标识了像素所用到的颜色数据。

DIB位图也有两种形式,即:底到上型DIB(bottom-up),和顶到下型DIB(top-down)。底到上型DIB的原点(origin)在图像的左下角,而顶到下型DIB的原点在图像的左上角。如果DIB的高度值(由BITMAPINFOHEADER结构中的biHeight成员标识)是一个正值,那么就表明这个DIB是一个底到上型DIB,如果高度值是一个负值,那么它就是一个顶到下型DIB。注意:顶到下型的DIB位图是不能被压缩的。

位图的颜色格式是通过颜色面板值(planes)和颜色位值(bitcount)计算得来的,颜色面板值永远是1,而颜色位值则可以是1、4、8、16、24、32其中的一个。如果它是1,则表示位图是一张单色位图(译者注:通常是黑白位图,只有黑和白两种颜色,当然它也可以是任意两种指定的颜色),如果它是4,则表示这是一张VGA位图,如果它是8、16、24、或是32,则表示该位图是其他设备所产生的位图。如果应用程序想获取当前显示设备(或打印机)的颜色位值(或称位深度),可调用API函数GetDeviceCaps(),并将第二个参数设为BITSPIXEL即可。
显示设备的分辩率是以每米多少个像素来表明的,应用程序可以通过以下三个步骤来获取显示设备或打印机的水平分辩率:
1. 调用GetDeviceCaps()函数,指定第二个参数为HORZRES。
2. 再次调用GetDeviceCaps()函数,指定第二个参数为HORZSIZE。
3. 用第一个返回值除以第二个返回值。即:DetDeviceCaps(hDC,HORZRES)/GetDeviceCaps(hDC,HORZSIZE);

应用程序也可以使用相同的三个步骤来获取设备的垂直分辩率,不同之处只是要将HORZRES替换为VERTRES,把HORZSIZE替换为VERTSIZE,即可。

调色板是被保存在一个RGBQUAD结构的数组中,该结构指出了每一种颜色的红、绿、蓝的分量值。位数组中的每一个索引都对应于一个调色板项(即一个RGBQUAD结构),应用程序将根据这种对应关系,将像素索引值转换为像素RGB值(真实的像素颜色)。应用程序也可以通过调用GetDeviceCaps()函数来获取当前显示设备的调色板尺寸(将该函数的第二个参数设为NUMCOLORS即可)。

Win32 API支持位数据的压缩(只对8位和4位的底到上型DIB位图)。压缩方法是采用运行长度编码方案(RLE),RLE使用两个字节来描述一个句法,第一个字节表示重复像素的个数,第二个字节表示重复像素的索引值。有关压缩位图的详细信息请参见对BITMAPINFOHEADER结构的解释。

应用程序可以从一个DDB位图创建出一个DIB位图,步骤是,先初始化一些必要的结构,然后再调用GetDIBits()函数。不过,有些显示设备有可能不支持这个函数,你可以通过调用GetDeviceCaps()函数来确定一下(GetDeviceCaps()函数在调用时指定RC_DI_BITMAP作为RASTERCAPS的标志)。

应用程序可以用DIB去设置显示设备上的像素(译者注:也就是显示DIB),方法是调用SetDIBitsToDevice()函数或调用StretchDIBits()函数。同样,有些显示设备也有可能不支持以上这两个函数,这时你可以指定RC_DIBTODEV作为RASTERCAPS标志,然后调用GetDeviceCaps()函数来判断该设备是否支持SetDIBitsToDevice()函数。也可以指定RC_STRETCHDIB作为RASTERCAPS标志来调用GetDeviceCaps()函数,来判断该设备是否支持StretchDIBits()函数。

如果应用程序只是要简单的显示一个已经存在的DIB位图,那么它只要调用SetDIBitsToDevice()函数就可以。比如一个电子表格软件,它可以打开一个图表文件,在窗口中简单的调用SetDIBitsToDevice()函数,将图形显示在窗口中。但如果应用程序要重复的绘制位图的话,则应该使用BitBlt()函数,因为BitBlt()函数的执行速度要比SetDIBitsToDevice()函数快很多。

设备相关位图 (Device-Dependent Bitmaps)

设备相关位图(DDB)之所以现在还被系统支持,只是为了兼容旧的Windows 3.0软件,如果程序员现在要开发一个与位图有关的程序,则应该尽量使用或生成DIB格式的位图。

DDB位图是被一个单个结构BITMAP所描述,这个结构的成员标明了该位图的宽度、高度、设备的颜色格式等信息。

DDB位图也有两种类型,即:可废弃的(discardable)DDB和不可废弃的(nondiscardable)DDB。可废弃的DDB位图就是一种当系统内存缺乏,并且该位图也没有被选入设备描述表(DC)的时候,系统就会把该DDB位图从内存中清除(即废弃)。不可废弃的DDB则是无论系统内存多少都不会被系统清除的DDB。API函数CreateDiscardableBitmap()函数可用于创建可废弃位图。而函数CreateBitmap()、CreateCompatibleBitmap()、和CreateBitmapIndirect()可用于创建不可废弃的位图。

应用程序可以通过一个DIB位图而创建一个DDB位图,只要先初始化一些必要的结构,然后再调用CreateDIBitmap()函数就可以。如果在调用该函数时指定了CBM_INIT标志,那么这一次调用就等价于先调用CreateCompatibleBitmap()创建当前设备格式的DDB位图,然后又调用SetDIBits()函数转换DIB格式到DDB格式。(可能有些设备并不支持SetDIBits()函数,你可以指定RC_DI_BITMAP作为RASTERCAPS的标志,然后调用GetDeviceCaps()函数来判断一下)。



位图、设备描述表、和绘图表面 (Bitmaps, Device Contexts, and Drawing Surfaces) 返回目录

设备描述表(DC)是一个定义图形目标的数据结构,包括图形的属性、映射模式等信息。应用程序可以调用CreateDC()函数来创建一个DC,它也可以调用GetDC()函数来获取一个窗口的DC。

绘图表面

在应用程序获得一个DC句柄之前,窗口将先选择一个“绘图表面”到DC中。如果应用程序是在一个VGA的显示设备上调用的CreateDC()函数,那么它获得的DC绘图表面尺寸就是640×480像素。如果应用程序是调用的GetDC()函数,则绘图表面的尺寸就等于窗口客户区的尺寸。

当应用程序使用由CreateDC()函数或GetDC()函数返回的DC句柄来进行绘图操作时(即用这个DC来调用绘图函数,如LineTo()函数),被请求的操作将出现在已选入该DC的绘图表面上。

兼容设备描述表 (Compatible Device Contexts)

先将图形在内存中画好,再一次性的输出到真实的显示设备上要比多次向显示设备上输出图形要快,并且程序更容易设计。为此,微软专门提供了一种特殊的设备描述表,称为兼容设备描述表(Compatible Device Context)(译者注:也叫作内存设备描述表)。Windows系统把兼容DC视为一种存在于内存中的虚拟设备。实质上兼容DC就是内存中的一个数组,应用程序可以把位图的颜色数据(即像素)保存于兼容DC中。

应用程序可以调用CreateCompatibleDC()函数来创建一个兼容设备描述表,该函数将返回一个DC句柄,你可以象使用真实设备DC一样来使用这个兼容DC。Windows系统在创建这种DC时,附加的也创建了一个1位的位图(即单色位图),并在CreateCompatibleDC()函数返回之前将该位图选入兼容DC中。所以应用程序在使用这个兼容DC之前,应先替换掉这个1位的位图。方法是,先调用CreateBitmap()、CreateBitmapIndirect()、或CreateCompatibleBitmap()函数来创建一个你所需要的位图(由你指定位图的尺寸及位深度),并获得一个位图句柄,然后调用SelectObject()函数将这个位图句柄选入兼容DC。在位图句柄被选入兼容DC之后,Windows系统将用一个足够大的位数组来替换掉原来的1位位图的位数组(译者注:请注意保存这个1位的位图,在绘图操作结束后还要选回)。此时,你就可以用该兼容DC来进行绘图操作了(比如:直线、曲线、文本、区域等操作),绘制的结果将被保存在兼容DC中的位数组中。但这个时候,这些结果你并不能马上看到,你应该调用BitBlt()函数将保存于兼容DC位数组中的图像拷贝到真实设备的绘图表面上(请注意,在调用BitBlt()函数时,要将兼容DC作为源DC,而将真实设备DC作为目标DC来调用)。

当你显示一个有调色板的DIB或DDB时(原始设备具有调色板),你可以通过适当的安排系统调色板来加快图像的显示速度。首先用NUMRESERVED作参数调用GetDeviceCaps()函数,来获取系统中保留的颜色个数。然后调用GetSystemPaletteEntries()函数,并用相应的系统颜色填充逻辑调色板开头和结尾的NUMRESERVED/2个调色板项。比如NUMRESERVED的返回值是20,则你必需用系统颜色填充逻辑调色板开头和结尾各10个项的调色板数据。然后再用位图的调色板来填充剩余的调色板项(这种调色板项必需设置PC_NOCOLLAPSE标志)。有关调色板和颜色的资料请参阅VC联机帮助中Colors一节。



位图的旋转 (Bitmap Rotation) 返回目录

Windows提供了一个函数,用于将矩形的位图拷贝到一个平行四边形中,这个函数就是PlgBlt()。在转换时,要将矩形位图DC作为源DC,而将平行四边形DC作为目标DC。有关旋转和World units(译者注:这个词未译出)的资料请参见VC联机帮助中Coordinate Spaces 和 Transformations 中的内容。



位图的比例缩放 (Bitmap Scaling) 返回目录

Win32 API也提供了一个按比例缩放位图的函数,它就是StretchBlt()。它可以将源设备描述表(DC)中的矩形位图传送到目标设备描述表中。但不同于BitBlt()函数,StretchBlt()允许应用程序指定源、目标位图的尺寸。如果应用程序指定的目标位图尺寸比源位图尺寸小,则系统将压缩源位图以符合目标位图尺寸。同时,你也可以指定该函数的压缩方式,使用SetStretchBitMode()函数。当目标位图的尺寸大于源位图时,系统将拉伸源位图(即扩大像素的颜色范围)以符合要求。



作为画刷的位图 (Bitmaps as Brushes) 返回目录

Win32 API中有几个函数是使用已选入DC中的画刷来进行位图操作的,比如:PatBlt()函数可在窗口的一个矩形区域中复制画刷,而FloodFill()函数则可以在窗口的一个非矩形区域中复制画刷(这个非矩形区域可以用指定颜色来圈定)。

PatBlt()函数的名字其实是一个缩写,全称应该是“图样块传送”(PATtern BLock Transfer, 缩写后就是PatBlt),从这个名字上看,它好像只是简单的复制画刷(或叫图样),直到填充完指定的矩形之后就结束了,其实这个函数可没有这么简单,它在复制画刷之前,将根据光珊操作码(raster operation,缩写是ROP)来组合图样中的像素与目标DC中相同位置上的像素而形成最终的图像。光珊操作码(ROP)在组合的过程中起到了非常重要的作用,实质上ROP是一种位操作符,一共有256种,PatBlt()函数可以接受那些需要图样和目标位图的ROP。下面的表格列出了该函数经常用到的5个ROP:

 ROP  描述 PATCOPY  拷贝图样到目标位图中 PATINVERT  用图样的像素或(即位操作OR)目标位图 DSTINVERT  将目标位图的像素值取反(即非目标图的像素值) BLACKNESS  将所有的输出都设为二进制的0 WHITENESS  将所有的输出都设为二进制的1

不同于PatBlt()函数,FloodFill()函数只是将选入DC的画刷简单的重复复制到一个由用户用指定颜色圈定的不规则区域中(填充满为止)。它不接受ROP命令。

 



位图的存储 (Bitmap Storage) 返回目录

如果用户想将位图保存到一个文件中,那么应用程序必需为该文件取一个以.BMP为后缀的扩展名,然后将位图以Windows位图文件格式保存到该文件当中。Windows位图文件格式由几部分组成,下表说明:

其中第一个结构BITMAPFILEHEADER包括了一些对位图文件的大致说明,比如:位图文件的标志“BM”、位图文件的尺寸、位数组的偏移等信息。第二个结构BITMAPINFOHEADER则指明了位图图像的宽度、高度、颜色格式(位面数,位深度)、压缩标志、原始设备分辩率等信息。再接下来的是RGBQUAD结构数组,它里面放置的是位图的调色板数据,每一个结构描述一个调色板项(包括红、绿、蓝的分量值)。(译者注:有些位图没有这个RGBQUAD数组,比如16位、24位、32位位图。而且有些位图文件将该数组所占空间移做它用,如16位、32位位图的BI_BITFIELD格式就将该空间作为三色掩码的存放处,编程时应注意区别)。

下面的表显示了一个BMP文件的实际内容:

0000 42 4d 76 02 00 00 00 00 00 00 76 00 00 00 28 00
0010 00 00 20 00 00 00 20 00 00 00 01 00 04 00 00 00
0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0030 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80
0040 00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80
0050 00 00 80 80 80 00 c0 c0 c0 00 00 00 ff 00 00 ff
0060 00 00 00 ff ff 00 ff 00 00 00 ff 00 ff 00 ff ff
0070 00 00 ff ff ff 00 00 00 00 00 00 00 00 00 00 00
0080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 09 00
0090 00 00 00 00 00 00 11 11 01 19 11 01 10 10 09 09
00a0 01 09 11 11 01 90 11 01 19 09 09 91 11 10 09 11
00b0 09 11 19 10 90 11 19 01 19 19 10 10 11 10 09 01
00c0 91 10 91 09 10 10 90 99 11 11 11 11 19 00 09 01
00d0 91 01 01 19 00 99 11 10 11 91 99 11 09 90 09 91
00e0 01 11 11 11 91 10 09 19 01 00 11 90 91 10 09 01
00f0 11 99 10 01 11 11 91 11 11 19 10 11 99 10 09 10
0100 01 11 11 11 19 10 11 09 09 10 19 10 10 10 09 01
0110 11 19 00 01 10 19 10 11 11 01 99 01 11 90 09 19
0120 11 91 11 91 01 11 19 10 99 00 01 19 09 10 09 19
0130 10 91 11 01 11 11 91 01 91 19 11 00 99 90 09 01
0140 01 99 19 01 91 10 19 91 91 09 11 99 11 10 09 91
0150 11 10 11 91 99 10 90 11 01 11 11 19 11 90 09 11
0160 00 19 10 11 01 11 99 99 99 99 99 99 99 99 09 99
0170 99 99 99 99 99 99 00 00 00 00 00 00 00 00 00 00
0180 00 00 00 00 00 00 90 00 00 00 00 00 00 00 00 00
0190 00 00 00 00 00 00 99 11 11 11 19 10 19 19 11 09
01a0 10 90 91 90 91 00 91 19 19 09 01 10 09 01 11 11
01b0 91 11 11 11 10 00 91 11 01 19 10 11 10 01 01 11
01c0 90 11 11 11 91 00 99 09 19 10 11 90 09 90 91 01
01d0 19 09 91 11 01 00 90 10 19 11 00 11 11 00 10 11
01e0 01 10 11 19 11 00 90 19 10 91 01 90 19 99 00 11
01f0 91 01 11 01 91 00 99 09 09 01 10 11 91 01 10 91
0200 99 11 10 90 91 00 91 11 00 10 11 01 10 19 19 09
0210 10 00 99 01 01 00 91 01 19 91 19 91 11 09 10 11
0220 00 91 00 10 90 00 99 01 11 10 09 10 10 19 09 01
0230 91 90 11 09 11 00 90 99 11 11 11 90 19 01 19 01
0240 91 01 01 19 09 00 91 10 11 91 99 09 09 90 11 91
0250 01 19 11 11 91 00 91 19 01 00 11 00 91 10 11 01
0260 11 11 10 01 11 00 99 99 99 99 99 99 99 99 99 99
0270 99 99 99 99 99 90


下面的表格说明各结构在上面的位图中所占的位置,可对照查看:

 结构   对应的字节范围 BITMAPFILEHEADER   0x00 - 0x0D   BITMAPINFOHEADER   0x0E - 0x35   RGBQUAD array   0x36 - 0x75   Color-index array   0x76 - 0x275 (译者注:Color-index array实际上就是位图的位数组)

 



使用位图 (Using Bitmap) 返回目录

捕获图像 (Capturing an Image) 返回目录

你可以用位图来捕获图像,并且可以将已捕获的图像保存到文件中,或是在窗口的其他位置显示该图像。在某些应用程序中,有些时候你也必需临时性的保存屏幕上的图像,比如在一个绘图程序中,如果用户选择了放大命令,那么你必需先保存当前屏幕上的图像,然后将图像放大,当用户再返回正常图像时,你就可以用原来保存的图像恢复到屏幕上了。

要想保存屏幕上的图像,你的应用程序必需先调用CreateCompatibleDC()函数来创建一个兼容于当前显示设备的DC,然后你再调用CreateCompatibleBitmap()函数来创建一个适当尺寸的位图,并把该位图选入上面那个DC中(使用SelectObject()函数)。当兼容设备描述表被创建,并且适当尺寸的位图也被选入了该DC之后,你就可以捕获图像了。Win32 API提供了BitBlt()函数来捕获图像,该函数起到了一个位块传输的作用—就是将源位图的位数据拷贝到目标位图中。因为该函数是在两个位图间传输数据,所以你可能以为它的入口参数是两个位图的句柄,但实际情况可不是这样,在BitBlt()函数的入口参数中你找不到位图句柄的参数,它实际上是通过设备描述表(DC)来进行操作的,源位图和目标位图的句柄都必需被选入源DC和目标DC中。在BitBlt()调用结束之后,源位图的数据就被拷贝到目标位图中了,你如果想显示这个图像,可再次调用BitBlt()函数,并把原来的目标DC作为源DC,把一个窗口DC(或打印机DC)作为目标DC即可。

下面的范例代码演示了怎样创建兼容DC、怎样创建位图、怎样将位图选入DC、以及怎样用BitBlt()函数捕捉图像(注:该段代码将捕获整个的桌面图像)。

/*  * Create a normal DC and a memory DC for the entire screen. The  * normal DC provides a "snapshot" of the screen contents. The  * memory DC keeps a copy of this "snapshot" in the associated  * bitmap.  */  hdcScreen = CreateDC("DISPLAY", NULL, NULL, NULL); hdcCompatible = CreateCompatibleDC(hdcScreen);  /* Create a compatible bitmap for hdcScreen. */  hbmScreen = CreateCompatibleBitmap(hdcScreen,                      GetDeviceCaps(hdcScreen, HORZRES),                      GetDeviceCaps(hdcScreen, VERTRES));  if (hbmScreen == 0)     errhandler("hbmScreen", hwnd);  /* Select the bitmaps into the compatible DC. */  if (!SelectObject(hdcCompatible, hbmScreen))     errhandler("Compatible Bitmap Selection", hwnd);          /* Hide the application window. */          ShowWindow(hwnd, SW_HIDE);          /*          * Copy color data for the entire display into a          * bitmap that is selected into a compatible DC.          */          if (!BitBlt(hdcCompatible,                0,0,                bmp.bmWidth, bmp.bmHeight,                hdcScreen,                0,0,                SRCCOPY))          errhandler("Screen to Compat Blt Failed", hwnd);          /* Redraw the application window. */          ShowWindow(hwnd, SW_SHOW);  

 



缩放图像 (scaling an Image) 返回目录

有一些应用程序(比如绘图软件)需要对图像进行放大或缩小处理,这时,应用程序就可以通过调用StretchBlt()函数来达到目的。与BitBlt()函数相同,StretchBlt()函数也是将源DC中的位图拷贝到目标DC中。但是,与BitBlt()函数不同的是,在StretchBlt()函数的入口参数中,应用程序可以指定源位图和目标位图的尺寸。如果指定的源位图尺寸大于指定的目标位图尺寸,则位图将被压缩,反之,位图将被放大。

如果指定的目标位图尺寸小于源位图尺寸,StretchBlt()函数将根据当前伸缩模式来删除一些像素,以使图像变小。下面的表格是所有的伸缩模式代码及它们的含意:

 伸缩模式码 含意 BLACKONWHITE 把待删除的像素与保留的像素进行逻辑与(AND)操作 WHITEONBLACK 把待删除的像素与保留的像素进行逻辑或(OR)操作 COLORONCOLOR 彻底删除待删除的像素 HALFTONE  以目标的颜色数据逼近源像素

你如果想设置伸缩模式,可调用SetStretchBltMode()函数。


下面的范例代码是从一个能将源图像放大两倍的程序中截取下来的(该应用程序使用的是缺省的伸缩模式,所以没有使用SetStretchBltMode()函数)。

    hdcScaled = CreateCompatibleDC(hdcScreen);      hbmScaled = CreateCompatibleBitmap(hdcScreen,                     GetDeviceCaps(hdcScreen, HORZRES) * 2,                     GetDeviceCaps(hdcScreen, VERTRES) * 2);      if (hbmScaled == 0)         errhandler("hbmScaled", hwnd);      /* Select the bitmaps into the compatible DC. */      if (!SelectObject(hdcScaled, hbmScaled))         errhandler("Scaled Bitmap Selection", hwnd);      case WM_COMMAND:     /* message: command from application menu */        switch(wParam) {          case IDM_SCALEX1:             if (fBlt){                  fScaled = FALSE;                  hdcWin = GetDC(hwnd);                  BitBlt(hdcWin,                     0,0,                     bmp.bmWidth, bmp.bmHeight,                     hdcCompatible,                     0,0,                     SRCCOPY);                  ReleaseDC(hwnd, hdcWin);             }             break;          case IDM_SCALEX2:             if (fBlt){                  fScaled = TRUE;                  StretchBlt(hdcScaled,                      0, 0,                      bmp.bmWidth * 2, bmp.bmHeight * 2,                      hdcCompatible,                      0, 0,                      bmp.bmWidth, bmp.bmHeight,                      SRCCOPY);                   hdcWin = GetDC(hwnd);                  BitBlt(hdcWin,                     0,0,                     bmp.bmWidth, bmp.bmHeight,                     hdcScaled,                     0,0,                     SRCCOPY);                  ReleaseDC(hwnd, hdcWin);             }             break; 


存储一幅图像 (Storing an Image) 返回目录

很多应用程序都需要将图像保存到文件当中,比如绘图程序要保存用户所画的图片,电子表格程序要保存用户的图表,CAD软件要保存图形,等等。

如果你的应用程序想以位映射的方式保存图像的话,你可以采用Windows操作系统的位图格式来保存。步骤是,先初始化BITMAPINFO结构(由BITMAPINFOHEADER结构和RGBQUAD结构数组组成),然后填写适当的数据用以说明待保存图像的各种参数。最后将BITMAPFILEHEADER结构及BITMAPINFO结构和位数组写入文件当中。

下面的范例代码演示了怎样初始化并填写BITMAPINFOHEADER结构:

PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp) {    BITMAP bmp;     PBITMAPINFO pbmi;    WORD    cClrBits;      /* Retrieve the bitmap's color format, width, and height. */      if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp))         errhandler("GetObject", hwnd);       /* Convert the color format to a count of bits. */      cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);    if (cClrBits == 1)         cClrBits = 1;    else if (cClrBits <= 4)        cClrBits = 4;     else if (cClrBits <= 8)         cClrBits = 8;    else if (cClrBits <= 16)         cClrBits = 16;    else if (cClrBits <= 24)         cClrBits = 24;     else         cClrBits = 32;          /*      * Allocate memory for the BITMAPINFO structure. (This structure      * contains a BITMAPINFOHEADER structure and an array of RGBQUAD data      * structures.)           */          if (cClrBits != 24)         pbmi = (PBITMAPINFO) LocalAlloc(LPTR,                     sizeof(BITMAPINFOHEADER) +                     sizeof(RGBQUAD) * (2^cClrBits));          /*  There is no RGBQUAD array for the 24-bit-per-pixel format. */      else         pbmi = (PBITMAPINFO) LocalAlloc(LPTR,                     sizeof(BITMAPINFOHEADER));        /* Initialize the fields in the BITMAPINFO structure. */      pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);     pbmi->bmiHeader.biWidth = bmp.bmWidth;     pbmi->bmiHeader.biHeight = bmp.bmHeight;     pbmi->bmiHeader.biPlanes = bmp.bmPlanes;     pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;    if (cClrBits < 24)         pbmi->bmiHeader.biClrUsed = 2^cClrBits;       /* If the bitmap is not compressed, set the BI_RGB flag. */      pbmi->bmiHeader.biCompression = BI_RGB;          /*      * Compute the number of bytes in the array of color      * indices and store the result in biSizeImage.     */      pbmi->bmiHeader.biSizeImage = (pbmi->bmiHeader.biWidth + 7) /8                                   * pbmi->bmiHeader.biHeight                                   * cClrBits;          /*      * Set biClrImportant to 0, indicating that all of the      * device colors are important.     */      pbmi->bmiHeader.biClrImportant = 0;    return pbmi;  } 

 

下面的范例将演示怎样打开一个文件,并拷贝数组、获取调色板索引、初始化保留结构、关闭文件等操作:

void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi,                   HBITMAP hBMP, HDC hDC)  {      HANDLE hf;                  /* file handle */     BITMAPFILEHEADER hdr;       /* bitmap file-header */     PBITMAPINFOHEADER pbih;     /* bitmap info-header */     LPBYTE lpBits;              /* memory pointer */     DWORD dwTotal;              /* total count of bytes */     DWORD cb;                   /* incremental count of bytes */     BYTE *hp;                   /* byte pointer */     DWORD dwTmp;       pbih = (PBITMAPINFOHEADER) pbi;     lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);    if (!lpBits)          errhandler("GlobalAlloc", hwnd);      /*      * Retrieve the color table (RGBQUAD array) and the bits      * (array of palette indices) from the DIB.      */      if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight,                    lpBits, pbi, DIB_RGB_COLORS))         errhandler("GetDIBits", hwnd);      /* Create the .BMP file. */      hf = CreateFile(pszFile,                    GENERIC_READ | GENERIC_WRITE,                    (DWORD) 0,                    (LPSECURITY_ATTRIBUTES) NULL,                    CREATE_ALWAYS,                    FILE_ATTRIBUTE_NORMAL,                    (HANDLE) NULL);      if (hf == INVALID_HANDLE_VALUE)         errhandler("CreateFile", hwnd);      hdr.bfType = 0x4d42;        /* 0x42 = "B" 0x4d = "M" */      /* Compute the size of the entire file. */      hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +                  pbih->biSize + pbih->biClrUsed                  * sizeof(RGBQUAD) + pbih->biSizeImage);      hdr.bfReserved1 = 0;     hdr.bfReserved2 = 0;      /* Compute the offset to the array of color indices. */      hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +                     pbih->biSize + pbih->biClrUsed                     * sizeof (RGBQUAD);      /* Copy the BITMAPFILEHEADER into the .BMP file. */      if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER),        (LPDWORD) &dwTmp, (LPOVERLAPPED) NULL))        errhandler("WriteFile", hwnd);      /* Copy the BITMAPINFOHEADER and RGBQUAD array into the file. */      if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER)                   + pbih->biClrUsed * sizeof (RGBQUAD),                   (LPDWORD) &dwTmp, (LPOVERLAPPED) NULL))        errhandler("WriteFile", hwnd);      /* Copy the array of color indices into the .BMP file. */      dwTotal = cb = pbih->biSizeImage;     hp = lpBits;     while (cb > MAXWRITE)  {             if (!WriteFile(hf, (LPSTR) hp, (int) MAXWRITE,                           (LPDWORD) &dwTmp, (LPOVERLAPPED) NULL))                 errhandler("WriteFile", hwnd);             cb-= MAXWRITE;             hp += MAXWRITE;     }     if (!WriteFile(hf, (LPSTR) hp, (int) cb,          (LPDWORD) &dwTmp, (LPOVERLAPPED) NULL))            errhandler("WriteFile", hwnd);      /* Close the .BMP file. */      if (!CloseHandle(hf))            errhandler("CloseHandle", hwnd);      /* Free memory. */    GlobalFree((HGLOBAL)lpBits);} 

 



位图操作函数列表 (Bitmap functions) 返回目录

下面是操作位图的各种函数,有兴趣的朋友可查看Win32 API手册。

 BitBlt() CreateBitmap() CreateBitmapIndirect() CreateCompatibleBitmap() CreateDIBitmap() CreateDIBSection() CreateDiscardableBitmap() ExtFloodFill() FloodFill() GetBitmapBits() GetBitmapDimensionEx() GetDIBColorTable() GetDIBits() GetPixel() GetStretchBltMode() LoadBitmap() MaskBlt() PatBlt() PlgBlt() SetBitmapBits() SetBitmapDimensionEx() SetDIBColorTable() SetDIBits() SetDIBitsToDevice() SetPixel() SetPixelV() SetStretchBltMode() StretchBlt() StretchDIBits()

 


与位图相关的结构 (Bitmap Structures)

 BITMAP BITMAPCOREHEADER BITMAPCOREINFO BITMAPFILEHEADER BITMAPINFO BITMAPINFOHEADER COLORADJUSTMENT DIBSECTION RGBQUAD RGBTRIPLE SIZE
(译者注:以上结构中,BITMAPINFO和BITMAPINFOHEADER的联机帮助内容非常重要,如果你想深入了解BMP的结构,就应该仔细研读一下)

 


与位图相关的宏 (Bitmap Macros)

MAKEROP4

 

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1516532


 

相关文章推荐

Photoshop学习资料-位图与矢量

  • 2010年12月15日 12:55
  • 982KB
  • 下载

工业自动化界面编程信号灯位图

  • 2017年06月30日 11:49
  • 16KB
  • 下载

位图和哈希切分的大数据处理

位图是一个数组的每个数据的每个二进制位表示一个数据,0表示数据不存在,1表示数据存在; 在现实生活中,大数据的处理十分的常见;比如说,给40亿个不重复的无符号整数,没排过序,如何快速判断一个数是否在这...

cocos2d-x位图字体生成工具bmfont

  • 2017年02月11日 13:57
  • 357KB
  • 下载

位图计算工具

  • 2016年07月10日 12:06
  • 459KB
  • 下载

数据结构之位图(bitmap)详解 (转)

1.  概述 位图(bitmap)是一种非常常用的结构,在索引,数据压缩等方面有广泛应用。本文介绍了位图的实现方法及其应用场景。 2. 位图实现 (1)自己实现 在位图中,...

iphone5 中文点位图.pdf

  • 2015年03月30日 07:25
  • 165KB
  • 下载

ProgressCtrlST位图进度条控件类

  • 2017年06月13日 15:15
  • 232KB
  • 下载

Potrace:一个基于多边形的位图轮廓矢量化算法

原文地址:http://linxinboy.blogbus.com 这是一个非常古老的算法 源于2003年,作者 Peter Selinger。 它的作用是输入一张二值图(不是黑就是白),输出此图的矢...

时间戳图片位图改数组

  • 2016年06月18日 15:18
  • 33KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:位图资料
举报原因:
原因补充:

(最多只允许输入30个字)