为什么显示DIB图时,如果不拉伸什么时候做,采用原始大小,源位图左上角区域坐标时这个?

位图与bitblt【位图知识】
位图和Bitblt
位图是一个二维的位数组,此数组的每一个元素与图像的像素一一对应。现实世界的图像被捕获以后,图像被分割成网格,并以像素作为取样单位。位图中的每个像素值指明了一个单位网格内图像的平均颜色。
位图代表了Windows程序中存储图像信息的两种方法之一,另一种形式是元文件。
位图也有两种:GDI位图对象和设备无关的位图(DIB: device-independent bitmap)。
位图常用来表示来自真实世界的复杂图像,元文件更适合于描述由人或者机器生成的图像。它们都能存于内存或作为文件存于磁盘上,且能通过剪贴板在Windows应用程序间传输。
位图和元文件的区别在于光栅图像和矢量图像间的差别。光栅图像用离散的像素来处理输出设备;矢量图像用笛卡尔坐标系统来处理输出设备,可在其中绘制线和填充对象。
位图的缺点:1、容易受设备依赖性的影响。2、位图常暗示了特定的显示分辨率和图像纵横比,在缩放后容易出现失真。3、存储空间大。
但位图具有处理速度快的优点。
位图可以手工创建,也可计算机代码生成,还可由硬件设备把现实世界输入到计算机,如数码相机,它们通常是使用接触到光就释放电荷的电荷耦合装置(CCD:
charge-coupled device)将光的强度转换为电荷,再用模数转换装置(ADC:
Analog-to-digital)转换为数字再排列为位图。
位图呈矩形,具有空间尺寸,以像素为单位度量位图的高度和宽度。以位于图像左上角为位图原点,从0开始计数。
位图的空间尺寸也指定了其分辨率,但此词具有争议,分辨率也指单位长度内的像素数。
位图是矩形的,但内存是线性的。大多数位图按行存储在内存中,且从顶行像素开始从左到右直到底行结束。
位图还有颜色度量单位:指每个像素所需要的位数,也称颜色深度(color
depth)、位数(bit-count)、或位/每像素(bpp: bits per
pixel)。每个像素用1位来描述的位图称为二级(bilevel)、二色(bicolor)或单色(monochrome)位图。每个像素也可用多位来描述,可以表示的颜色数等于2的i次方(i为位数)。
如何将颜色位的组合与人们所熟识的颜色相对应是处理位图时经常出现的问题。
一、BitBlt函数:原样复制
整个视频显示器可看作是一幅大位图,其上的像素由存储在视频显示适配卡上内存中的位来描述。所以,我们可以使用BitBlt函数来完成将图像从视频显示的一个区域复制到另一个区域。这就是位块传送(bit-block
tranfer)。此函数是像素移动程序,实际上对像素执行了一次位运算操作。
BitBlt函数从称为“源”的设备描述表中将一个矩形区的像素传送到称为“目标”的另一个设备描述表中相同大小的矩形区。源和目标设备描述表可以相同。此函数语法如下:
BitBlt(hdcDst,xDst,yDst,cx,cy,hdcSrc,xSrc,ySrc,dwROP);
xSrc和ySrc参数指明了源图像左上角在源设备描述表中的坐标位置。cx和cy是图像的宽度和高度。xDst和yDst是图像复制到的设备描述表中的坐标位置。dwROP是光栅操作符。
  注意:BitBlt是从实际视频显示内存传送像素,也就是说整个显示屏上的图像都存于显存中,若图像超出了显示屏,那么BitBlt只传送在显示屏上的部分。
BitBlt的最大限制是两个设备描述表必须兼容,就是说两者的每个像素都具有相同的位数。所以,不能用它将屏幕上的某些图形复制到打印机。
二、StretchBlt函数:拉伸位图
此函数语法如下:StretchBlt(hdcDst,xDst,yDst,cxDst,cyDst,
hdcSrc,xSrc,ySrc,cxSrc,cySrc,dwROP);
BitBlt和StretchBlt函数中所有的坐标与大小都是基于逻辑单位的。但如果BitBlt函数中有两个不同的设备描述表,而这两个设备描述表引用相同的物理设备却具有不同的映射模式时,BitBlt就不明确了:cx和cy都是逻辑单位,它们同样应用于源设备描述表和目标设备描述表中的矩形区。此时,所有的坐标和尺寸必须在实际的位传送之前转换为设备坐标。cx和cy同时用于源和目标设备描述表,所以必须分别转换为设备描述表自己的单位。(?)
三、PatBlt函数:绘制填充图形
语法如下:PatBlt(hdc,x,y,cx,cy,dwROP);
GDI位图对象:也称为设备相关位图或者DDB
一、创建DDB
DDB是Windows图形设备接口的图形对象之一(其中还包括画笔、画刷、字体、元文件和调色板)。这些图形对象保存在GDI模式内部,由应用程序软件的数字句柄引用。用HBITMAP类型的变量存储DDB句柄:HBITMAP
hBitmap。然后通过调用某个创建DDB的函数来获得句柄,这有三个函数。这些函数分配并初始化GDI内存中的一些内存来存储关于位图的信息,以及实际位图的位信息。应用程序不能直接访问这段内存。位图与设备描述表无关。程序使用完位图以后,就清除这段内存:DeleteObject(hBitmap);
三个函数:
CreateBitmap(cx,cy,cPlanes,cBitsPixel,bits);
CreateCompatibleBitmap(hdc,cx,cy);创建一个与设备兼容的位图。
CreateBitmapIndirect(&bitmap);bitmap是BITMAP类型的结构。
二、位图位
获得和设置像素位:
GetBitmapBits(hBitmap,cBytes,&bits);
SetBitmapBits(hBitmap,cBytes,&bits);
cBytes指明要复制的字节数,bits是其大小至少为cBytes的缓冲区。
像素实际上并不涉及任何固定的颜色,它只是一个值,与在视频板上的调色板查找表是的索引值有关。
基本的规则:不要用CreateBitmap、CreateBitmapIndirect或SetBitmapBits来设置彩色DDB的位,只能安全地设置单色DDB的位。
三、内存设备描述表
设备描述表指的是某个图形输出设备(如显示器或打印机),及其设备驱动程序。
内存设备描述表只位于内存中,它不是真正的图形输出设备,但可以说与某个实际设备“兼容”。在有某个实际设备的设备描述表之后,就可以创建内存设备描述表:
hdcMem=CreateCompatibleDC(hdc);
如果其参数为NULL,则创建一个与显示器相兼容的内存设备描述表。最后用DeleteDC来清除。
内存设备描述表有一个与实际光栅设备相同的、单色、1像素宽、1像素高的显示表面。然后,通过将一个GDI位图对象选进内存设备描述表来完成扩大显示表面的工作:SelectObject(hdcMem,hBitmap);
内存设备描述表是唯一一种可以选进位图的设备描述表。SelectObject调用以后,DDB就是内存设备描述表的显示表面。可以在其上进行各种处理实际设备描述表的每项操作。
批注:内存设备描述表实际上提供了一种在内存和显示器间进行位图传送的方法。
四、加载位图资源
也可用LoadBitmap函数来获得GDI位图对象句柄。
五、单色位图格式
对于单色位图,可以用一个字节数组来描述位图中的各个像素。
先用BITMAP结构来定义位图的信息,再用BYTE类型的数组来定义各个像素定义的各个位,最后用CreateBitmap、CreateBitmapIndirect来创建位图。
与设备无关的位图
DDB的位格式高度依赖于设备,所以它不适用于图像交换。DDB内没有色彩表来指定位图的位与色彩之间的联系,它仅当在Windows会话的生存期内被创建和清除时才有意义。
设备无关的位图(DIB)提供了适用于交换的图像文件格式。DIB内的位图几乎没有被压缩,适用于在程序中直接操作。如果在内存中有DIB,就可以提供指向该DIB的指针作为某些函数的参数,来显示DIB或把DIB转化为DDB。
DIB文件格式
DIB作为一种文件格式,它的扩展名为.BMP,在极少数的情况下为.DIB。Windows使用的位图图像被当作DIB文件创建,并作为只读资源存储在程序的可执行文件中。
程序能将DIB文件减去前14个字节加载到连续的内存块中形成“紧缩DIB(packed-DIB)格式的位图”。程序可以使用紧缩DIB格式,通过Windows剪帖板来交换图像或创建画刷,也或完全访问DIB的内容,并以任意方式修改DIB。
一、OS/2风格的DIB
DIB文件有4个主要的部分:
 文件头、信息头、RGB色彩表(不一定有)和位图像素位。
前两部分保看成是一种C的数据结构,第三部分是数据结构的数组。
对内存中紧缩的DIB格式只有3个部分,就是缺少文件头。
DIB文件以14个字节的BITMAPFILEHEADER结构的文件头开始,指出了文件的类型、文件大小及像素位的偏移量;此后是12个字节的BITMAPCOREHEADER结构,指出了DIB的大小及每像素的位数。
BITMAPCOREHEADER结构中的bcBitCount字段一般为1、4、8或24,分别对应2色、16色、256色和全色的DIB。对于前三种BITMAPCOREHEADER后紧跟色彩表,对24位DIB,则无色彩表。
色彩表是一个RGBTRIPLE结构(此结构每个为3字节大小)的数组,数组中的每个元素代表图像中的每种颜色(指这种图像由多少种颜色来描述,如8位图就有256种颜色,这256种颜色就由这个数组的各个元素来指定,这个数组的大小就是256)。
二、从下向上
DIB中的像素位是按水平行组织的,常称“扫描线”。行数为BITMAPCOREHEADER结构中的bcHeight字段。但DIB从图像的底行开始,从下往上扫过图像。
所以,在DIB中,图像的底行是文件的第一行,图像的顶行是文件的最后一行。这个文件的第一行指的是DIB文件的色彩表后的位图像素位的第一个像素行,最后一行是位图像素位的最后一行。
三、DIB像素位
DIB文件的最后部分由实际的DIB的像素位组成。像素位是由从图像的底行开始,并沿着图像向上增长的水平行组织的。DIB中的行数为BITMAPCOREHEADER结构的bcHeight字段,每行的像素数为该结构的bcWidth字段。每行从最左边的像素数开始,直到图像的右边。每个像素的位数可以从bcBitCount字段获取,为1、4、8或24。 
1位DIB:每字节为8像素,最左边的像素是第一个字节的最高位,色彩表中有2项。
4位DIB:每字节为2像素,最左边的像素是第一个字节的高4位,色彩表中有16项。
8位DIB:每字节为1像素,色彩表中有256项。
24位DIB:每3字节表示1个像素,每个字节代表红、绿和蓝的颜色值,就可以描述三种颜色的256个值,所以这个DIB无色彩表。
四、扩展的Windows DIB
这种DIB格式与前面的格式一样,以BITMAPFILEHEADER结构开始,但是接着是40字节的BITMAPINFOHEADER结构,而不是12字节的BITMAPCOREHEADER结构。另一个变化是:对于使用BITMAPINFOHEADER结构的1位、4位和8位DIB,色彩表不是RGBTRIPLE结构的数组,而是4字节的RGBQUAD结构的数组。
BITMAPINFOHEADER结构的biClrUsed是非常重要的字段,它影响色彩表中条目的数量,对于4位和8位的DIB,它能分别指出色彩表的条目数小于16或256个;对于16位、24位或32位DIB也可以为非0,在这种情况下Windows不使用色彩表来解释像素位,但它指出DIB中色彩表的大小,程序使用该信息来设置调色板在256显示器上显示DIB。
总结如下:
对于1位DIB,biClrUsed始终是0或2。色彩表始终有2个条目。
对于4位DIB,如果biClrUsed是0或16,则色彩表有16个条目,如果是从2到15的数,则指的是色彩表中的条目数。每个像素值的最大值比该数小1。
对于8位DIB,如果biClrUsed是0或256,则色彩表有256个条目,如果是从2到255的数,则指的是色彩表中的条目数。每个像素值的最大值比该数小1。
对于16位、24位或32位DIB,biClrUsed通常为0。如果不为0,则指的是色彩表中的条目数。运行于256色视频适配器的应用程序使用这些条目来为DIB设置调色板。
由上可知,对于1、4、8和24位的DIB,像素位的组织与OS/2兼容的DIB是相同的,但在后来的DIB中,24位DIB可以有色彩表了。
五、8位灰度DIB
8位DIB分为两类:灰度DIB和混色DIB。
若某些灰度DIB中有一个等于64的biClrUsed字段,则指出了色彩表中有64个条目,这些条目通常以上升的灰度级排列,也就是说色彩表中红绿蓝值相等时,这时若为8位,则其具有整个灰度组成的色彩表,这时,像素值自身就代表了灰色的程度(但不是说像素值与实际的RGB值相等),所以进行某些图像处理时,仅需处理像素值就可以了。
六、DIB压缩
BITMAPINFOHEADER结构的biCompression字段可以为4个常量之一,它们是:BI_RGB、BI_RLE8、BI_RLE4或BI_BIFIELDS,在WINGDI.H头文件中有定义,值分别为0,1,2,3。此字段有两个用途:对于4位和8位DIB,指出像素位用一种行程编码方式压缩了;对于16位和32位DIB,指出颜色掩蔽是否用于对像素位进行编码。
1、& 行程编码(run-length: RLE压缩):对4位和8位
对于1位和24位DIB,biCompression字段始终是BI_RGB;对于4位和8位DIB,此字段是BI_RGB,像素位存储方式和前面的DIB一样,若是BI_RLE4或BI_RLE8,则使用行程编码。
行程编码是根据DIB映像在一行内经常有相同的像素串这个事实进行压缩的。
8位DIB的RLE:解码时,成对查看DIB数据字节。
(1)&&&&&&&&&&&&&
如果第一个字节非0,则它就是行程的重复因子,随后的像素值被重复多次。如,对0x05 0x27,解码后为0x27 0x27 0x27
(2)&&&&&&&&&&&&&
如果第二字节为n=0x03-0xFF中的一个,则说明要使用接下来的n个像素值。如,序列0x00 0x06 0x45 0x32 0x77
0x34 0x59 0x90,则解码后为0x45 0x32 0x77 0x34 0x59
0x90。由于总是两字节地检查,所以这此序列总是以2字节边界排列,所以若第二字节为奇数,则序列内就有一个未用的多余字节,如,0x00
0x05 0x45 0x32 0x77 0x34 0x59 0x00,则解码后为0x45 0x32 0x77 0x34
(3)&&&&&&&&&&&&&
若2字节为00
02,则后面的2字节分别为dx和dy指出了在现有的(x,y)[这对数字在开始时为(0,0),在解码时,每对一个像素解码,x的值加1,每完成一行就将x置0,y加1]这个解码位置上移到(x+dx,y+dy)上。
(4)&&&&&&&&&&&&&
若2字节为00 01和00 00,分别说明图像结束和行结束。
对于4位DIB的RLE编码方法相同,但字节和像素之间不是一对一的关系,如,序列0x07 0x35 0x05
0x24,则解码为0x35 0x35 0x35 0x32 0x42 0x42
2、& 颜色掩蔽(color masking) :对16位和32位DIB
  在biCompression字段为BI_RGB时:
16位DIB编码方式:红、绿、蓝三种颜色各使用5位,对于行内的第一个像素,蓝色值是第1字节的最低5位。绿色值在第一和第二字节中都有位:绿色值的两个最高位是第二个字节中的两个最低位,绿色值的3个最低位是第一个字节的3个最高位。红色值是第二个字节中的2到6位。第二个字节的最高位是0。之所以要这样安排,是因为在以16位字访问像素值时,应先取低字节,在取完二个字节后形成的像素值以红、绿、蓝排列。
32位DIB编码方式:由于每个字节是4字节,所以前三个字节为红、绿、蓝,最后字节为0。
在biCompression字段为BI_BITFIELDS时:紧跟DIB的BITMAPINFOHEADER结构的是三个32位颜色掩码,分别用于红、绿、蓝。然后用C的按位与操作符(&)把这些掩码应用于16位或32位的像素值上。
打开和显示
两个函数:SetDIBitsToDevice和StretchDIBits
它们都使用存储在内存中的DIB,并能显示整个DIB或它的矩形部分。当使用SetDIBitsToDevice时,以像素为单位显示的图像大小与DIB的像素大小相同。StretchDIBits则能缩放DIB尺寸的行和列,从而在输出设备上显示一个特定的大小。
1、两个函数的需要
DIB文件能被加载到内存中。如果除了文件头外,整个文件被存储在连续的内存块中,那么指向该块开始的指针被称作指向紧缩DIB的指针。
SetDIBitsToDevice和StretchDIBits函数需要的信息包括一个指向DIB的BITMAPINFO结构的指针,也即指向紧缩DIB的指针,还有就是一个指向像素位的指针。之所以要两个指针,是因为这两部分在内存的两个块中。除了这两个指针,还需要DIB的像素高度和宽度。
2、像素到像素:SetDIBitsToDevice函数
此函数显示DIB,并不对其进行拉伸或缩放。DIB的每个像素映射到输出设备的一个像素上。要调用SetDIBitsToDevice函数来显示整个DIB图像,需要下列信息:
hdc 目标表面的设备描述表句柄;
xDst和yDst 图像左上角的目标坐标;
cxDib和cyDib DIB的像素宽度和高度,cyDib是BITMAPINFOHEADER结构内biHeight字段的绝对值;
pInfo和pBits 指向位图信息部分和像素位的指针。
  3、DIB的颠倒:从下向上的DIB的原点是位图图像的左下角,它是位图数据的第一行的第一个像素。从上向下的DIB的原点也是位图图像的左上角,但左下角是位图数据的最后一行的第一个像素。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。博客访问: 148009
博文数量: 73
博客积分: 0
博客等级: 民兵
技术积分: 919
注册时间:
我喜欢蓝天,也喜欢雨天。
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: Windows平台
1.位图和元文件是windows中存储图像信息的两种方式。位图是一个二维数组,与图像的像素一一对应。元文件是对图像的描述而不是数字化。位图与元文件的区别在于光栅图像(用离散的像素来处理输出设备)与矢量图像(用笛卡尔坐标系统来处理输出设备)的差别。
位图容易受设备依赖性的影响,并且存储空间大,但是速度快。
元文件可以移动独立的图形对象,比如一条直线,对图像缩放不失真。
位图可以手工创建,也可以由计算机生成.
2.设备相关位图 DDB(Device-Dependent-Bitmap)
DDB不具有自己的调色板信息,他的颜色模式必须与输出设备相一致。如:在256色以下的位图中存储的像素值是系统调色板的索引,其颜色依赖于系统调色板。由于DDB高度依赖输出设备,所以DDB只能存在于内存中,它要么在视频内存中,要么在系统内存中。
3.设备无关位图DIB(Device-Independent-Bitmap)
DIB具有自己的调色板信息,他可以不依赖系统的调色板。由于他不依赖于设备,所以通常用它保存文件。这是一种文件格式,是为了保证用某个应用程序创建的位图图形可以被其它应用程序装载或显示一样。&
DIB的与设备无关性主要体现在以下两个方面:DIB的颜色模式与设备无关。例如,一个256色的DIB即可以在真彩色显示模式下使用,也可以在16色模式下使用。256色以下(包括256色)的DIB拥有自己的颜色表,像素的颜色独立于系统调色板。由于DIB不依赖于具体设备,因此可以用来永久性地保存图象。DIB一般是以*.BMP文件的形式保存在磁盘中的,有时也会保存在*.DIB文件中。运行在不同输出设备下的应用程序可以通过DIB来交换图象。
DDB必须是单色的或是与真实输出设备相同的格式。DIB是一个文本或者内存块;DDB是GDI位图对象并由位图句柄表示。DIB能被显示或转换为DDB,并转换回DIB,但是这里包含了设备无关和设备相关位之间的转换过程。
4.BitBlt 代表“位块传送”,将图像从视频显示的一个区域复制到另一个区域,此函数实际上对像素执行了一次位运算操作。目标图像和源图像的尺寸是相同的。
5.StretchBlt 在复制时拉伸或压缩图像尺寸,还允许水平或垂直翻转图像。参数坐标都是逻辑单位。
6.光栅操作:是像素的位操作。
8.HBITMAP hB
hBitmap = CreateBitmap();创建DDB的函数来获得句柄。
CreateBitmapIndirect();
9.内存设备描述表:
只位于内存,不是真正的图形输出设备,但可以说与某个实际设备"兼容".
10.加载位图资源: hBitmap = LoadBitmap(hInstance, szBitmapName);
11.影子位图:是位图的缓冲
1.设备无关位图DIB(Device-Independent-Bitmap)
DIB具有自己的调色板信息,他可以不依赖系统的调色板。由于他不依赖于设备,所以通常用它保存文件。这是一种文件格式,是为了保证用某个应用程序创建的位图图形可以被其它应用程序装载或显示一样。
DIB的与设备无关性主要体现在以下两个方面:DIB的颜色模式与设备无关。例如,一个256色的DIB即可以在真彩色显示模式下使用,也可以在16色模式下使用。256色以下(包括256色)的DIB拥有自己的颜色表,像素的颜色独立于系统调色板。由于DIB不依赖于具体设备,因此可以用来永久性地保存图象。DIB一般是以*.BMP文件的形式保存在磁盘中的,有时也会保存在*.DIB文件中。运行在不同输出设备下的应用程序可以通过DIB来交换图象。
2.紧缩DIB格式的位图
DIB文件减去前14个字节加载到连续的内存块中,这时就可以称它为“紧缩DIB格式的位图”.
3.DIB 文件有4个主要部分:
文件头&& 14个字节
RGB 色彩头(不一定有)
位图像素位
4.DIB从图像的底行开始,往上扫过图像。
5.显示DIB: 像素到像素
SetDIBitsToDevice ( hdc, // 设备环境句柄
&&&&&&&&&&&&&&&&&&&&& 0, // 目标矩形左上角的X轴坐标,按逻辑单位表示坐标
&&&&&&&&&&&&&&&&&&&&& 0, // 目标矩形左上角的Y轴坐标
&&&&&&&&&&&&&&&&&&&&& bitmap24bit.bitmapinfoheader.biWidth, // 位图宽度,按逻辑单位表示宽度
&&&&&&&&&&&&&&&&&&&&& bitmap24bit.bitmapinfoheader.biHeight, // 位图高度,按逻辑单位表示高度
&&&&&&&&&&&&&&&&&&&&& 0, // 位图左下角的X轴坐标,按逻辑单位表示坐标
&&&&&&&&&&&&&&&&&&&&&&0, // 位图左下角的Y轴坐标,按逻辑单位表示坐标
&&&&&&&&&&&&&&&&&&&&& 0, //DIB中的起始扫描线
&&&&&&&&&&&&&&&&&&&&& bitmap24bit.bitmapinfoheader.biHeight, // DIB扫描线数目
&&&&&&&&&&&&&&&&&&&&& (BYTE*)bitmap24bit.buffer, //位图数据区起始指针,是BYTE*类型.
&&&&&&&&&&&&&&&&&&&&& (BITMAPINFO*)(&(bitmap24bit.bitmapinfoheader)),//位图的BITMAPINFO指针.这里要特别注意,因为Load_Bitmap_File函数使用的数据结构中没有BITMAPINFO结构,所以用BITMAPINFOHEADER来转变的.
&&&&&&&&&&&&&&&&&&&&& DIB_RGB_COLORS) ; //最后一个是颜色使用类型.
StretchDIBits 可以缩放DIB尺寸的行和列,或以特定大小显示。
6.与设备有关的位图(DDB)和与设备无关的位图(DIB)类似设备坐标和逻辑坐标。
阅读(485) | 评论(0) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。《Windows 程序设计》学习之旅(110)
摘录于《Windows程序(第5版,珍藏版).CHarles.Petzold 著》P711
&&&&&&& 在前面的章节中,我们学习了 GDI 位图对象、设备无关位图、DIB 区块,以及 Windows 调色板管理器。在这些知识的武装下,现在我们可以设计一组库函数,来帮助我们对位图进行操作。
&&&&&&& 前面的 PACKEDIB 文件给出了一种可能的方法:通过一个指向头结构的指针来访问位图的信息。但是,这种方式对像素操作(“get pixel” 和 “set pixel”)的执行效率不高,因而不能满足通常的图像处理任务要求。我们需要一种方式,既能方便地访问位图信息,又能快速地进行像素操作。
&&&&&&& 一种可能的 C++ 解决方案是,创建一个 DIB 类,用其中的一个成员变量存放指向紧凑 DIB 的指针;其他成员变量和成员函数可帮助实现获取及设置 DIB 中像素的快速例程。但是既然我在本书第一章已经指明,你只需要了解 C 就可以贯通本书,因此 C++ 的解决方案就只能留给其他书了。
&&&&&&& 当然,C++ 能做的 C 也能够做到。大量使用句柄的 Windows 函数就是很好的例子。应用程序除了知道句柄是一个数值以外,还知道什么呢?它知道这个句柄用于引用一个特定的对象,而且存在使用该对象的函数。很明显,操作系统利用该句柄以某种方式来引用这个对象的内部信息。句柄可以和指向结构的指针一样简单。
&&&&&&& 比如说,假设有一组函数使用一个叫 HDIB 的句柄。HDIB 是什么呢?它有可能在某个头文件中被定义为:
typedef void * HDIB;这个定义回答了“HDIB是什么”的问题——“与你无关”。
&&&&&&& 而实际上,一个 HDIB 可能是一个指向结构的指针,该结构中除了包含紧凑 DIB 指针外,还有其他一些信息:
typedef struct
BITMAPINFO * pBackedD
cx, cy, cBitsPerPixel, cBytesPerR
DIBSTRUCTURE, * PDIBSTRUCTURE
该结构的其他五个字段包含了从紧凑 DIB 得到的信息,而把它们放在结构中则可以更快速地访问这些信息。DIB 库的各种函数都可以使用这个结构,而不是使用 pPackedDib 指针。一个 DIbGetPixelPointer 函数可以这样实现:
BYTE * DibGetPixelPointer (HDIB hdib, int x, int y)
PDIBSTRUCTURE pdib =
return pdib-&pBits + y * pdib-&cBytesPerRow +
x * pdb-&cBitsPerPixel / 8;
显然,上面的代码比起 PACKEDIB.C 中可能实现的“获取像素”的例程,其速度要快得多。
&&&&&&& 尽管这种方法很合理,但我决定放弃紧凑 DIB 而基于 DIB 区块来实现我的 DIB 库。这样做,我们不仅保持了紧凑 DIB 的所有灵活性(即按照某种设备无关的方式进行 DIB 像素位的操作),而且在 Windows NT 下执行速度更快。
16.4.1& DIBSTRUCT 结构
&&&&&&& DIBHELP.C 文件是一个超过 1000 行的程序,顾名思义,它用于提供 DIB 操作方面的帮助,很快我们将分几部分介绍它。这里,先让我们看看 DIBHELP 函数使用的结构,该结构定义如下:
typedef struct
// array of row pointers
// = &Dib &
// handle returned from CreateDIBSection
// pinter to bitmap bits
DIBSECTION
// DIBSECTION structure
iRShift[3];
// right-shift values for color masks
iLShift[3];
// left-shift values for color masks
DIBSTRUCT, * PDIBSTRUCT;
&&&&&&& 现在我们先略过第一个字段。它之所以是第一个字段是因为它能使某些宏操作更容易,而在先介绍其他字段之后再回过头来介绍它会更容易理解。
&&&&&&& 该结构中的第二个字段在初始化时(由 DIBHELP.C 中的某个 DIB 创建函数执行)被设置为文本串“Dib”的二进制形式,一些 DIBHELP 函数用它来验证这个结构指针的有效性。
&&&&&&& 该结构中的第三个字段——hBitmap——存储了 CreateDIBSection 函数返回的位图句柄,和第 14 章的 GDI 位图句柄一样,它可用于各种不同的操作。不同的一点是,这个由 CreateDIBSection 返回的句柄指向的位图是以设备无关的格式存储的,直到它被 BitBlt 或 StretchBlt 调用传给输出设备。
&&&&&&& DIBSTRUCT 结构中的第四个字段存储了一个指向位图位的指针,它的值也在 CreateDIBSection 函数中设定。如上文所述,存储位图的内存块由操作系统管理,但应用程序可以访问该内存块。该内存块在位图句柄被删除后会自动释放。
&&&&&&& DIBSTRUCT 结构中的第五个字段是一个 DIBSECTION 结构。如前文所述,从 CreateDIBSection 得到的位图句柄可以传给 GetObject 函数,以便获取 DIBSECTION 结构中有关位图的信息:
GetObject (hBitmap, sizeof (DIBSECTION), &ds);
&&&&&&& 在此提醒你,DIBSECTION 结构在 WINGDI.H 中是如下定义的:
typedef struct tagDIBSECTION {
BITMAPINFOHEADER
dsBitfields[3];
// Color masks
DIBSECTION, * PDIBSECTION;
第一个字段是一个 BITMAP 结构,CreateBitmapIndirect 用这个类型来创建一个位图对象;GetObject 函数用这个类型来获取设备相关位图 (DDB) 的信息。第二个字段是一个 BITMAPINFOHEADER 结构。无论传给 CreateDIBSection 函数的位图信息结构如何,DIBSECTION 结构将总是包含一个 BITMAPINFOHEADER
结构(而非 BITMAPCOREHEADER)。这就意味着,DIBHELP.C 中的很多函数在访问这一结构时不必考虑 OS/2 的兼容问题。
&&&&&&& 你应该记得,对于 16 位或 32 位 DIB,如果 BITMAPINFOHEADER 结构中的字段 biCompression 被设置为 BI_BITFIELDS,就意味着我们需要使用三个掩码转换图像的格式为 RGB 色彩模式。这三个掩码通常被存储在 BITMAPINFOHEADER 结构后,DIBSECTION 结构中第三个字段就用来存储这三个掩码。
&&&&&&& DIBSECTION 结构中的最后两个字段用于从文件创建设备无关位图。我们的库 DIBHELP 没有用到这个功能,所以也用不到这两个字段。
&&&&&&& DIBSTRUCT 结构中最后两个字段存储左移位和右移位的值,用于位图编码格式的转换,我们在第 15 章讨论过它们的用法。
&&&&&&& 让我们再回到 DIBSTRUCT 结构的第一个字段(PBYTE * ppRow),当 DIB 首次建立时,这个字段就被设置成一个指向指针数组的指针。在这个指针数组中,每个指针都指向位图中的一行像素。利用这些指针,我们可以更快访问像素信息。数组的第一个指针指向位图中的最上面的一行像素,最后一个指针指向 DIB 图像的最下面的一行(和 DIBSTRUCT 结构中的 pBits 字段一样)。
16.4.2& 信息获取函数
&&&&&&& DIBHELP.C 的开始定义了 DIBSTRUCT 结构,并提供了一组函数用于帮助应用程序获取 DIB 区块的信息。图 16-20 给出了 DBHELP.C 的第一部分。
DIBHELP.C (第 1 部分)
/*------------------------------------------
    DIBHELP.C -- DIB Section Helper Routine
                 (c) Charles Petzold, 1998
------------------------------------------*/
#include &Windows.h&
#include &DibHelp.h&
#define HDIB_HDIB_SIGNATURE (* (int *) &Dib &)
typedef struct&pre name=&code& class=&cpp&&SIGNATURE
    PBYTE        * ppR        // must be first field for macros!
    int              iS
    HBITMAP          hB
    BYTE        * pB
    DIBSECTION     
    int              iRShift[3];
    int              iLShift[3];
DIBSTRUCT, * PDIBSTRUCT;
/*-----------------------------------------------------------------
    DibIsValid: Returns TRUE if hdib points to a valid DIBSTRUCT
-----------------------------------------------------------------*/
BOOL DibIsValid(HDIB hdib)
    PDIBSTRUCT pdib = (PDIBSTRUCT)
    if (pdib == NULL)
        return FALSE;
    if (IsBadReadPtr(pdib, sizeof(DIBSTRUCT)))
        return FALSE;
    if (pdib-&iSignature != HDIB_SIGNATURE)
        return FALSE;
    return TRUE;
/*----------------------------------------------------------------------
    DibBitmapHandle: Returns the handle to the DIB section bitmap object
----------------------------------------------------------------------*/
HBITMAP DibBitmapHandle(HDIB hdib)
    if (!DibIsValid(hdib))
        return NULL;
    
    return ((PDIBSTRUCT)hdib)-&hB
/*-------------------------------------------
    DibWidth: Returns the bitmap pixel width
-------------------------------------------*/
int DibWidth(HDIB hdib)
    if (!DibIsValid(hdib))
        return 0;
    return ((PDIBSTRUCT)hdib)-&ds.dsBm.bmW
/*---------------------------------------------
    DibHeight: Returns the bitmap pixel height
---------------------------------------------*/
int DibHeight(HDIB hdib)
    if (!DibIsValid(hdib))
        return 0;
    return ((PDIBSTRUCT)hdib)-&ds.dsBm.bmH
/*-----------------------------------------------------
    DibBitCount: Returns the number of bits per pixel
-----------------------------------------------------*/
int DibBitCount(HDIB hdib)
    if (!DibIsValid(hdib))
        return 0;
    return ((PDIBSTRUCT)hdib)-&ds.dsBm.bmBitsP
/*--------------------------------------------------------------
    DibRowLength: Returns the number of bytes per row of pixels
--------------------------------------------------------------*/
int DibRowLength(HDIB hdib)
    if (!DibIsValid(hdib))
        return 0;
    return 4 * ((DibWidth(hdib) * DibBitCount(hdib) + 31) / 32);
/*-----------------------------------------------------------------
    DibNumColors: Returns the number of colors in the color table
-----------------------------------------------------------------*/
int DibNumColors(HDIB hdib)
    PDIBSTRUCT pdib = (PDIBSTRUCT)
    if (!DibIsValid(hdib))
        return 0;
    if (pdib-&ds.dsBmih.biClrUsed != 0)
    {
        return pdib-&ds.dsBmih.biClrU
    }
    else if (DibBitCount(hdib) &= 8)
    {
        return 1 && DibBitCount(hdib);
    }
    return 0;
/*------------------------------------------
    DibMask: Returns one of the color masks
-------------------------------------------*/
DWORD DibMask(HDIB hdib, int i)
    PDIBSTRUCT pdib = (PDIBSTRUCT)
    if (!DibIsValid(hdib) || i & 0 || i & 2)
        return 0;
    return pdib-&ds.dsBitfields[i];
/*---------------------------------------------------
    DibRShfit: Returns one of the right-shift values
---------------------------------------------------*/
int DibRShift(HDIB hdib, int i)
    PDIBSTRUCT pdib = (PDIBSTRUCT)
    if (!DibIsValid(hdib) || i & 0 || i & 2)
        return 0;
    return pdib-&iRShift[i];
/*---------------------------------------------------
    DibLShfit: Returns one of the left-shift values
---------------------------------------------------*/
int DibLShift(HDIB hdib, int i)
    PDIBSTRUCT pdib = (PDIBSTRUCT)
    if (!DibIsValid(hdib) || i & 0 || i & 2)
        return 0;
    return pdib-&iLShift[i];
}    
/*-----------------------------------------------------------------
    DibCompression: Returns the value of the biCompression field
-----------------------------------------------------------------*/
int DibCompression(HDIB hdib)
    if (!DibIsValid(hdib))
        return 0;
    return ((PDIBSTRUCT)hdib)-&ds.dsBmih.biC
/*-----------------------------------------------------------------
    DibIsAddressable: Returns TRUE if the DIB is not compressed
-----------------------------------------------------------------*/
BOOL DibIsAddressable(HDIB hdib)
    int iC
    if (!DibIsValid(hdib))
        return FALSE;
    iCompression = DibCompression(hdib);
    if (iCompression == BI_RGB || iCompression == BI_BITFIELDS)
        return TRUE;
    return FALSE;
/*---------------------------------------------------------------------------
    These functions return the sizes of various components of the DIB section
        AS THEY WOULD APPEAR in a packed DIB. These functions aid in converting
        the DIB section to a packed DIB and in saving DIB files.
----------------------------------------------------------------------------*/
DWORD DibInfoHeaderSize(HDIB hdib)
    if (!DibIsValid(hdib))
        return 0;
    
    return ((PDIBSTRUCT)hdib)-&ds.dsBmih.biS
DWORD DibMaskSize(HDIB hdib)
    PDIBSTRUCT pdib = (PDIBSTRUCT)
    if (!DibIsValid(hdib))
        return 0;
    if (pdib-&ds.dsBmih.biCompression == BI_BITFIELDS)
        return 3 * sizeof(DWORD);
    return 0;
DWORD DibColorSize(HDIB hdib)
    return DibNumColors(hdib) * sizeof(RGBQUAD);
DWORD DibInfoSize(HDIB hdib)
    return DibInfoHeaderSize(hdib) + DibMaskSize(hdib) + DibColorSize(hdib);
DWORD DibBitsSize(HDIB hdib)
    PDIBSTRUCT pdib = (PDIBSTRUCT)
    if (!DibIsValid(hdib))
        return 0;
    if (pdib-&ds.dsBmih.biSizeImage != 0)
    {
        return pdib-&ds.dsBmih.biSizeI
    }
    return DibHeight(hdib) * DibRowLength(hdib);
DWORD DibTotalSize(HDIB hdib)
    return DibInfoSize(hdib) + DibBitsSize(hdib);
/*-----------------------------------------------------------------------
    These functions return pointers to the various components of the DIB
        section.
-----------------------------------------------------------------------*/
BITMAPINFOHEADER * DibInfoHeaderPtr(HDIB hdib)
    if (!DibIsValid(hdib))
        return NULL;
    return &(((PDIBSTRUCT)hdib)-&ds.dsBmih);
DWORD * DibMaskPtr(HDIB hdib)
    PDIBSTRUCT pdib = (PDIBSTRUCT)
    if (!DibIsValid(hdib))
        return 0;
    return pdib-&ds.dsB
void * DibBitsPtr(HDIB hdib)
    if (!DibIsValid(hdib))
        return NULL;
    return ((PDIBSTRUCT)hdib)-&pB
/*-------------------------------------------------------
    DibGetColor: Obtains entry from the DIB color table
--------------------------------------------------------*/
BOOL DibGetColor(HDIB hdib, int index, RGBQUAD * prgb)
    PDIBSTRUCT    pdib = (PDIBSTRUCT)
    HDC            hdcM
    int            iR
    if (!DibIsValid(hdib))
        return 0;
    hdcMem = CreateCompatibleDC(NULL);
    SelectObject(hdcMem, pdib-&hBitmap);
    iReturn = GetDIBColorTable(hdcMem, index, 1, prgb);
    DeleteDC(hdcMem);
    return iReturn ? TRUE : FALSE;
/*-------------------------------------------------------
    DibSetColor: Sets an entry in the DIB color table
--------------------------------------------------------*/
BOOL DibSetColor(HDIB hdib, int index, RGBQUAD * prgb)
    PDIBSTRUCT    pdib = (PDIBSTRUCT)
    HDC            hdcM
    int            iR
    if (!DibIsValid(hdib))
        return 0;
    hdcMem = CreateCompatibleDC(NULL);
    SelectObject(hdcMem, pdib-&hBitmap);
    iReturn = SetDIBColorTable(hdcMem, index, 1, prgb);
    DeleteDC(hdcMem);
    return iReturn ? TRUE : FALSE;
&&&&&&& DIBHELP.C 中,大部分函数都一目了然,不需讲述。DibIsValid 函数是整个系统的“防弹衣”,其他函数调用它来确保 DIBSTRUCT 结构的有效性。所有这些函数的第一个并且通常只有一个 HDIB 参数,我们很快将看到,它是一个在 DIBHELP.H 定义为 void 类型的指针。函数通常把它转换为 PDIBSTRUCT 类型的指针,并通过它来访问 DIBSTRUCT 结构中的字段。
&&&&&&& 注意,DibIsAddressable 函数返回值的类型是 BOOL。这个函数也可以称为 DibIsNotCompressed 函数。其返回值指出一个位图是否可以被寻址(即不能压缩)。
&&&&&&& 以调用 DibInfoHeaderSize 开始的一组函数用于获取 DIB 区块中各部分的大小。这些函数可以用来将一个 DIB 区块转换为紧凑的 DIB 存于内存中,或存于文件中。下面的一组函数用于获取 DIB 中各部分的指针。
&&&&&&& 在 DIBHELP.C 中,虽然有一个叫 DibInfoHeaderPtr 的函数用于获取 BITMAPINFOHEADER 结构的指针,但是并没有一个函数可以获取 BITMAPINFO 结构(紧跟着位图颜色表定义的那个结构)的指针。这是因为应用程序没有直接访问这类结构的权限。虽然我们可以访问定义在 DIBSECTION 中的 BITMAPINFOHEADER 的结构和颜色掩码,并能通过 CreateDIBSection 返回的指针访问像素信息,但DIB
颜色表只能间接通过调用 GetDIBColorTable 和 SetDIBColorTable 来访问。这两函数被封装在 DIBHELP 的 DibGetColor 和 DibSetColor 函数里。
&&&&&&& 在 DIBHELP.C 稍后部分,DibCopyToInfo 返回一个指向 BITMAPINFO 结构的指针并为这个结构填信息,但这个指针和取得内存中现有结构的指针并不完全一样。
16.4.3& 读/写像素信息
&&&&&&& 使用紧凑 DIB 或 DIB 区块的很大一个好处是应用程序可以直接操作设备独立位图的像素。图 16-21 中,DIBHELP.C 的第二部分代码便是为此目的提供的函数。
DIBHELP.C (第 2 部分)
/*-----------------------------------------------------------------
    DibPixelPtr: Returns a pointer to the pixel at position (x, y)
------------------------------------------------------------------*/
BYTE * DibPixelPtr(HDIB hdib, int x, int y)
    if (!DibIsAddressable(hdib))
        return NULL;
    if (x & 0 || x &= DibWidth(hdib) || y & 0 || y &= DibHeight(hdib))
        return NULL;
    return (((PDIBSTRUCT)hdib)-&ppRow)[y] + (x * DibBitCount(hdib) && 3);
/*-----------------------------------------------
    DibGetPixel: Obtains a pixel value at (x, y)
------------------------------------------------*/
DWORD DibGetPixel(HDIB hdib, int x, int y)
    PBYTE pP
    if (!(pPixel = DibPixelPtr(hdib, x, y)))
        return 0;
    switch (DibBitCount(hdib))
    {
    case 1: return 0x01 & (*pPixel && (7 - (x & 7)));
    case 4: return 0x0F & (*pPixel && (x & 1 ? 0 : 4));
    case 8: return *pP
    case 16: return *(WORD *)pP
    case 24: return 0x00FFFFFF & * (DWORD *)pP
    case 32: return *(DWORD *)pP
    }
    return 0;
/*-----------------------------------------------
    DibSetPixel: Sets a pixel value at (x, y)
------------------------------------------------*/
BOOL DibSetPixel(HDIB hdib, int x, int y, DWORD dwPixel)
    PBYTE pP
    if (!(pPixel = DibPixelPtr(hdib, x, y)))
        return FALSE;
    switch (DibBitCount (hdib))
    {
    case 1: *pPixel &= ~(1 && (7 - (x & 7)));
            *pPixel |= dwPixel && (7 - (x & 7));
            
    case 4: *pPixel &= 0x0F && (x & 1 ? 4 : 0);
            *pPixel |= dwPixel && (x & 1 ? 0 : 4);
            
    case 8: *pPixel = (BYTE)dwP
            
    case 16: *(WORD *)pPixel = (WORD)dwP
            
    case 24: *(RGBTRIPLE *)pPixel = *(RGBTRIPLE *)&dwP
            
    case 32: *(DWORD *)pPixel = dwP
            
    default:
        return FALSE;
    }
    return TRUE;
/*------------------------------------------------------
    DibGetPixelColor: Obtains the pixel color at (x, y)
-------------------------------------------------------*/
BOOL DibGetPixelColor(HDIB hdib, int x, int y, RGBQUAD * prgb)
    DWORD        dwP
    int            iBitC
    PDIBSTRUCT    pdib = (PDIBSTRUCT)
        // G also use this as a validity check
    if (0 == (iBitCount = DibBitCount(hdib)))
        return FALSE;
        // Get the pixel value
    dwPixel = DibGetPixel(hdib, x, y);
        // If the bit-count is 8 or less, index the color table
    if (iBitCount &= 8)
        return DibGetColor(hdib, (int)dwPixel, prgb);
        // If the bit-count is 24, just use the pixel
    else if (iBitCount == 24)
    {
        *(RGBTRIPLE *)prgb = *(RGBTRIPLE *)& dwP
        prgb-&rgbReserved = 0;
    }
        // If the bit-count is 32 and the biCompression field is BI_RGB,
        //        just use the pixel
    else if (iBitCount == 32 &&
        pdib-&ds.dsBmih.biCompression == BI_RGB)
    {
        *prgb = *(RGBQUAD *)& dwP
    }
        // Otherwise, use the mask and shift values
        //    (for best performance, don't use DibMask and DibShift functions)
    else
    {
        prgb-&rgbRed = (BYTE)(((pdib-&ds.dsBitfields[0] & dwPixel)
                            && pdib-&iRShift[0]) && pdib-&iLShift[0]);
        prgb-&rgbGreen = (BYTE)(((pdib-&ds.dsBitfields[1] & dwPixel)
                            && pdib-&iRShift[1]) && pdib-&iLShift[1]);
        prgb-&rgbBlue = (BYTE)(((pdib-&ds.dsBitfields[2] & dwPixel)
                            && pdib-&iRShift[2]) && pdib-&iLShift[2]);
    }
    return TRUE;
/*------------------------------------------------------
    DibSetPixelColor: Sets the pixel color at (x, y)
-------------------------------------------------------*/
BOOL DibSetPixelColor(HDIB hdib, int x, int y, RGBQUAD * prgb)
    DWORD        dwP
    int            iBitC
    PDIBSTRUCT    pdib = (PDIBSTRUCT)
        // Don't do this function for DIBs with color tables
    iBitCount = DibBitCount(hdib);
    if (iBitCount &= 8)
        return FALSE;
        //    The rest is just the opposite of DibGetPixelColor
    else if (iBitCount == 24)
    {
        *(RGBTRIPLE *)& dwPixel = *(RGBTRIPLE *)
        dwPixel &= 0x00FFFFFF;
    }
    else if (iBitCount == 32 &&
        pdib-&ds.dsBmih.biCompression == BI_RGB)
    {
        *(RGBQUAD *)& dwPixel = *
    }
    else
    {
        dwPixel = (((DWORD)prgb-&rgbRed && pdib-&iLShift[0])
                        && pdib-&iRShift[0]);
        dwPixel |= (((DWORD)prgb-&rgbGreen && pdib-&iLShift[1])
                        && pdib-&iRShift[1]);
        dwPixel |= (((DWORD)prgb-&rgbBlue && pdib-&iLShift[2])
                        && pdib-&iRShift[2]);
    }
    DibSetPixel(hdib, x, y, dwPixel);
    return TRUE;
&&&&&&& DIBHELP.C 这部分首先是一个 DibPixelPtr 函数,用来获取存储特定像素的内存指针。如前文所述,DIBSTRUCT 结构的 ppRow 字段是一个指向从上向下排列的 DIB 像素行的指针。因此,以下指针是指向位图中最上面一行最左边像素的指针:
((PDIBSTRUCT) hdib)-&ppRow)[0];而以下指针是指向位于(x, y)的像素的指针:
((PDIBSTRUCT) hdib)-&ppRow)[y] + (x * DibBitCount (hdib) && 3);需要注意的是,如果 DIB 不可寻址(即压缩的),或者 x 和 y 参数是负值或指向 DIB 外面的区域,DibPixelPtr 函数就返回一个 NULL 值。这些检查降低了 DibPixelPtr 函数(以及任何调用 DibPixelPtr 的函数)的运行速度,后面我会介绍如何改进。
&&&&&&& 文件中随后出现的函数 DibGetPixel 和 DibSetPixel 就利用了 DibPixelPtr。对于 8 位、16 位和 32 位的位图,这些函数只需要把指针转换到相应的数据位,就可以访问像素值。对于 1 位和 4 位的位图,则需要使用掩码和移位操作。
&&&&&&& DibGetColor 函数用于读取像素点的颜色,其结果被放在 RGBQUAD 结构中。对于 1 位、4 位和 8 位的位图,其 RGB 色值需要通过位图的颜色表来查找。对于 16 位、24 位和 32 位的位图,RGB 色值可通过掩码和移位操作从像素数据得出。DibSetColor 的功能正好相反,我们可以通过这个函数来设定像素点的颜色。这个函数只用于 16 位、24 位和 32 位的位图。
16.4.4& 创建和转换
&&&&&&& 图 16-22 所示的 DIBHELP 库的第三部分(也是最后一部分)说明了如何创建 DIB 区块,如何与紧凑 DIB 进行相互转换。
(第 3 部分)
/*---------------------------------------------------------------
    Calculating shift values from color masks is required by the
        DibCreateFromInfo function.
----------------------------------------------------------------*/
static int MaskToRShift(DWORD dwMask)
    int iS
    if (dwMask == 0)
        return 0;
    for (iShift = 0; !(dwMask & 1); iShift++)
        dwMask &&= 1;
    return iS
static int MaskToLShift(DWORD dwMask)
    int iS
    if (dwMask == 0)
        return 0;
    while (!(dwMask & 1))
        dwMask &&= 1;
    for (iShift = 0; dwMask & 1; iShift++)
        dwMask &&= 1;
    return 8 - iS
/*--------------------------------------------------------------------------
    DibCreateFromInfo: All DIB creation functions ultimately call this one.
        This function is responsible for calling CreateDIBSection, allocating
        memory for DIBSTRUCT, and setting up the row pointer.
--------------------------------------------------------------------------*/
HDIB DibCreateFromInfo(BITMAPINFO * pbmi)
    BYTE        * pB
    DIBSTRUCT    *
    HBITMAP          hB
    int              i, iRowLength, cy,
    hBitmap = CreateDIBSection(NULL, pbmi, DIB_RGB_COLORS, (VOID**)&pBits, NULL, 0);
    if (hBitmap == NULL)
        return NULL;
    if (NULL == (pdib = (PDIBSTRUCT)malloc(sizeof(DIBSTRUCT))))
    {
        DeleteObject(hBitmap);
        return NULL;
    }
    pdib-&iSignature = HDIB_SIGNATURE;
    pdib-&hBitmap = hB
    pdib-&pBits = pB
    GetObject(hBitmap, sizeof(DIBSECTION), &pdib-&ds);
        // Notice that we can now use the DIB information functions
        //    defined above.
        // If the compression is BI_BITFIELDS, calculate shifts from masks
    if (DibCompression(pdib) == BI_BITFIELDS)
    {
        for (i = 0; i & 3; i++)
        {
            pdib-&iLShift[i] = MaskToLShift(pdib-&ds.dsBitfields[i]);
            pdib-&iRShift[i] = MaskToRShift(pdib-&ds.dsBitfields[i]);
        }
    }
        // If the compression is BI_RGB, but bit-count is 16 or 32,
        // set the bitfields and the masks
    else if (DibCompression(pdib) == BI_RGB)
    {
        if (DibBitCount(pdib) == 16)
        {
            pdib-&ds.dsBitfields[0] = 0x00007C00;
            pdib-&ds.dsBitfields[1] = 0x;
            pdib-&ds.dsBitfields[2] = 0x0000001F;
            pdib-&iRShift[0] = 10;
            pdib-&iRShift[1] = 5;
            pdib-&iRShift[2] = 0;
            pdib-&iLShift[0] = 3;
            pdib-&iLShift[1] = 3;
            pdib-&iLShift[2] = 3;
        }
        else if (DibBitCount(pdib) == 24 || DibBitCount(pdib) == 32)
        {
            pdib-&ds.dsBitfields[0] = 0x00FF0000;
            pdib-&ds.dsBitfields[1] = 0x0000FF00;
            pdib-&ds.dsBitfields[2] = 0x000000FF;
            pdib-&iRShift[0] = 16;
            pdib-&iRShift[1] = 8;
            pdib-&iRShift[2] = 0;
            pdib-&iLShift[0] = 0;
            pdib-&iLShift[1] = 0;
            pdib-&iLShift[2] = 0;
        }
    }
        
        // Allocate an array of pointers to each row in the DIB
    cy = DibHeight(pdib);
    if (NULL == (pdib-&ppRow = (PBYTE *)malloc(cy * sizeof(BYTE *))))
    {
        free(pdib);
        DeleteObject(hBitmap);
        return NULL;
    }
        // Initialize them.
    iRowLength = DibRowLength(pdib);
    if (pbmi-&bmiHeader.biHeight & 0)        // ie, bottom up
    {
        for (y = 0; y & y++)
            pdib-&ppRow[y] = pBits + (cy - y - 1) * iRowL
    }
    else                                    // top down
    {
        for (y = 0; y & y++)
            pdib-&ppRow[y] = pBits + y * iRowL
    }
    
/*--------------------------------------------------
    DibDelete: Frees all memory for the DIB section
---------------------------------------------------*/
BOOL DibDelete(HDIB hdib)
    DIBSTRUCT * pdib = (DIBSTRUCT *)
    if (!DibIsValid(hdib))
        return FALSE;
    free(pdib-&ppRow);
    DeleteObject(pdib-&hBitmap);
    free(pdib);
    return TRUE;
/*-----------------------------------------------------
    DibCreate: Creates an HDIB from explicit arguments
-----------------------------------------------------*/
HDIB DibCreate(int cx, int cy, int cBits, int cColors)
    BITMAPINFO    *
    DWORD          dwInfoS
    HDIB          hD
    int              cE
    if (cx &= 0 || cy &= 0 ||
        ((cBits != 1) && (cBits != 4) && (cBits != 8) &&
        (cBits != 16) && (cBits != 24) && (cBits != 32)))
    {
        return NULL;
    }
    if (cColors != 0)
        cEntries = cC
    else if (cBits &= 8)
        cEntries = 1 && cB
    dwInfoSize = sizeof(BITMAPINFO) + (cEntries - 1) * sizeof(RGBQUAD);
    if (NULL == (pbmi = (PBITMAPINFO)malloc(dwInfoSize)))
    {
        return NULL;
    }
    ZeroMemory(pbmi, dwInfoSize);
    pbmi-&bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pbmi-&bmiHeader.biWidth =
    pbmi-&bmiHeader.biHeight =
    pbmi-&bmiHeader.biPlanes = 1;
    pbmi-&bmiHeader.biBitCount = cB
    pbmi-&bmiHeader.biCompression = BI_RGB;
    pbmi-&bmiHeader.biSizeImage = 0;
    pbmi-&bmiHeader.biXPelsPerMeter = 0;
    pbmi-&bmiHeader.biYPelsPerMeter = 0;
    pbmi-&bmiHeader.biClrUsed = cC
    pbmi-&bmiHeader.biClrImportant = 0;
    hDib = DibCreateFromInfo(pbmi);
    free(pbmi);
    return hD
/*-----------------------------------------------------
    DibCopyToInfo: Builds BITMAPINFO structure.
                    Used by DibCopy and DibCopyToDdb
-----------------------------------------------------*/
static BITMAPINFO * DibCopyToInfo(HDIB hdib)
    BITMAPINFO    *
    int              i, iNumC
    RGBQUAD        *
    if (!DibIsValid(hdib))
        return NULL;
        // Allocate the memory
    if (NULL == (pbmi = (BITMAPINFO*)malloc(DibInfoSize(hdib))))
        return NULL;
        // Copy the information header
    CopyMemory(pbmi, DibInfoHeaderPtr(hdib), sizeof(BITMAPINFOHEADER));
        // Copy the possible color masks
    prgb = (RGBQUAD *)((BYTE *)pbmi + sizeof(BITMAPINFOHEADER));
    if (DibMaskSize(hdib))
    {
        CopyMemory(prgb, DibMaskPtr(hdib), 3 * sizeof(DWORD));
        prgb = (RGBQUAD*)((BYTE*)prgb + 3 * sizeof(DWORD));
    }
        // Copy the color table
    iNumColors = DibNumColors(hdib);
    for (i = 0; i & iNumC i++)
        DibGetColor(hdib, i, prgb + i);
    
/*-------------------------------------------------------------------
    DibCopy: Creates a new DIB section from an existing DIB section,
        possibly swapping the DIB
--------------------------------------------------------------------*/
HDIB DibCopy(HDIB hdibSrc, BOOL fRotate)
    BITMAPINFO    *
    BYTE        * pBitsSrc, * pBitsD
    HDIB          hdibD
    if (!DibIsValid(hdibSrc))
        return NULL;
    if (NULL == (pbmi = (BITMAPINFO *)DibCopyToInfo(hdibSrc)))
        return NULL;
    if (fRotate)
    {
        pbmi-&bmiHeader.biWidth = DibHeight(hdibSrc);
        pbmi-&bmiHeader.biHeight = DibWidth(hdibSrc);
    }
    hdibDst = DibCreateFromInfo(pbmi);
    free(pbmi);
    if (hdibDst == NULL)
        return NULL;
        // Copy the bits
    if (!fRotate)
    {
        pBitsSrc = (BYTE*)DibBitsPtr(hdibSrc);
        pBitsDst = (BYTE*)DibBitsPtr(hdibDst);
        CopyMemory(pBitsDst, pBitsSrc, DibBitsSize(hdibSrc));
    }
    return hdibD
/*-------------------------------------------------------------------------
    DibCopyToPackedDib is generally used for saving DIBs and for
        transferring DIBs to the clipboard. In the second case, the second
        argument should be set to TRUE so that the memory is allocated
        with the GMEM_SHARE flag.
--------------------------------------------------------------------------*/
BITMAPINFO * DibCopyToPackedDib(HDIB hdib, BOOL fUseGlobal)
    BITMAPINFO    * pPackedD
    BYTE        * pB
    DWORD          dwDibS
    HDC              hdcM
    HGLOBAL          hG
    int              iNumC
    PDIBSTRUCT      pdib = (PDIBSTRUCT)
    RGBQUAD        *
    if (!DibIsValid(hdib))
        return NULL;
        // Allocate memory for packed DIB
    dwDibSize = DibTotalSize(hdib);
    if (fUseGlobal)
    {
        hGlobal = GlobalAlloc(GHND | GMEM_SHARE, dwDibSize);
        pPackedDib = (BITMAPINFO*)GlobalLock(hGlobal);
    }
    else
    {
        pPackedDib = (BITMAPINFO*)malloc(dwDibSize);
    }
    if (pPackedDib == NULL)
        return NULL;
        // Copy the information header
    CopyMemory(pPackedDib, &pdib-&ds.dsBmih, sizeof(BITMAPINFOHEADER));
    prgb = (RGBQUAD *)((BYTE *)pPackedDib + sizeof(BITMAPINFOHEADER));
        // Copy the possible color masks
    if (pdib-&ds.dsBmih.biCompression == BI_BITFIELDS)
    {
        CopyMemory(prgb, pdib-&ds.dsBitfields, 3 * sizeof(DWORD));
        prgb = (RGBQUAD *)((BYTE *)prgb + 3 * sizeof(DWORD));
    }
        
        // Copy the color table
    if (iNumColors = DibNumColors(hdib))
    {
        hdcMem = CreateCompatibleDC(NULL);
        SelectObject(hdcMem, pdib-&hBitmap);
        GetDIBColorTable(hdcMem, 0, iNumColors, prgb);
        DeleteDC(hdcMem);
    }
    pBits = (BYTE *)(prgb + iNumColors);
        // Copy the bits
    CopyMemory(pBits, pdib-&pBits, DibBitsSize(pdib));
        // If last argument is TRUE, unlock global memory block and
        //    cast it to pointer in preparation for return
    if (fUseGlobal)
    {
        GlobalUnlock(hGlobal);
        pPackedDib = (BITMAPINFO *)hG
    }
    return pPackedD
/*-------------------------------------------------------------------------
    DibCopyFromPackedDib is generally used for pasting DIBs from the
        clipboard.
--------------------------------------------------------------------------*/
HDIB DibCopyFromPackedDib(BITMAPINFO * pPackedDib)
    BYTE        * pB
    DWORD          dwInfoSize, dwMaskSize, dwColorS
    int              iBitC
    PDIBSTRUCT     
        // Get the size of the information header and do validity check
    dwInfoSize = pPackedDib-&bmiHeader.biS
    if (dwInfoSize != sizeof(BITMAPCOREHEADER) &&
        dwInfoSize != sizeof(BITMAPINFOHEADER) &&
        dwInfoSize != sizeof(BITMAPV4HEADER) &&
        dwInfoSize != sizeof(BITMAPV5HEADER))
    {
        return NULL;
    }
        // Get the possible size of the color masks
    if (dwInfoSize == sizeof(BITMAPINFOHEADER) &&
        pPackedDib-&bmiHeader.biCompression == BI_BITFIELDS)
    {
        dwMaskSize = 3 * sizeof(DWORD);
    }
    else
    {
        dwMaskSize = 0;
    }
        // Get the size of the color table
    if (dwInfoSize == sizeof(BITMAPCOREHEADER))
    {
        iBitCount = ((BITMAPCOREHEADER *)pPackedDib)-&bcBitC
        if (iBitCount &= 8)
        {
            dwColorSize = (1 && iBitCount) * sizeof(RGBTRIPLE);
        }
        else
            dwColorSize = 0;
    }
    else                // all non-OS/2 compatible DIBs
    {
        if (pPackedDib-&bmiHeader.biClrUsed & 0)
        {
            dwColorSize = pPackedDib-&bmiHeader.biClrUsed * sizeof(RGBQUAD);
        }
        else if (pPackedDib-&bmiHeader.biBitCount &= 8)
        {
            dwColorSize = (1 && pPackedDib-&bmiHeader.biBitCount) *
                                                    sizeof(RGBQUAD);
        }
        else
        {
            dwColorSize = 0;
        }
    }
        // Finally, get the pointer to the bits in the packed DIB
    pBits = (BYTE *)pPackedDib + dwInfoSize + dwMaskSize + dwColorS
        // Create the HDIB from the packed-DIB pointer
    pdib = (PDIBSTRUCT)DibCreateFromInfo(pPackedDib);
        // Copy the pixel bits
    CopyMemory(pdib-&pBits, pBits, DibBitsSize(pdib));
    
/*-----------------------------------------------------
    DibFileLoad: Creates a DIB section from a DIB file
------------------------------------------------------*/
HDIB DibFileLoad(const TCHAR * szFileName)
    BITMAPFILEHEADER 
    BITMAPINFO        *
    BOOL              bS
    DWORD              dwInfoSize, dwBitsSize, dwBytesR
    HANDLE              hF
    HDIB              hD
    // Open the file: read access, prohibit write access
    hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
        OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
        return NULL;
    // Read in the BITMAPFILEHEADER
    bSuccess = ReadFile(hFile, &bmfh, sizeof(BITMAPFILEHEADER),
        &dwBytesRead, NULL);
    if (!bSuccess || (dwBytesRead != sizeof(BITMAPFILEHEADER))
        || (bmfh.bfType != *(WORD *) &BM&))
    {
        CloseHandle(hFile);
        return NULL;
    }
    // Allocate memory for the information structure & read it in
    dwInfoSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
    if (NULL == (pbmi = (BITMAPINFO*)malloc(dwInfoSize)))
    {
        CloseHandle(hFile);
        return NULL;
    }
    bSuccess = ReadFile(hFile, pbmi, dwInfoSize, &dwBytesRead, NULL);
    if (!bSuccess || (dwBytesRead != dwInfoSize))
    {
        CloseHandle(hFile);
        free(pbmi);
 &#1}

我要回帖

更多关于 cad同时拉伸 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信