结构体
DIB文件有四个主要部分:
文件头(file hearder)
位图信息头(information header)
RGB颜色表(RGB color table),24位位图没有
位图像素(bitmap pixel bits)
DIB在内存中的格式只有后面三个部分,没有文件头。
DIB的结构体都定义在WINGDI.H头文件中。
文件头结构体(bmfh): 结构体大小为14。bfType是文件格式标志,“BM”表示是位图,值为0x4D42。bfSize是整个文件的大小,接下来两个保留字段为0,如果是鼠标位图,则用这两个字段表示鼠标的“热点(Hot spot)“,bfOffsetBits是位图开始位置的偏移量。
位图基本(核心)信息头结构体(bmch): bcSize是bmch结构体大小,等于12。bcWidth和bcHeight为图片分辨率,bcPlanes总为1。bcBitCount是1,4,8或24,是像素位数,如果为24,则为真彩色,bmch后面直接就是位图,没有颜色表。
RGB三元组结构体(rgbt):
在WINGDI.H中,还定义了位图基本(核心)信息结构体(bmci):这个结构体只定义了一个颜色,实际中没有用,我们使用的位图颜色只能是2,16或256。如果要定义一个8位位图的基本信息,可以用下面的方法: ,可以用pbmci->bmciColors[i]来访问任意颜色。
扩展DIB的位图信息头结构体(bmih): 这个结构体共40字节,前五个字段和位图基本信息头(bmch)一样,但bcWidth和bcHeight为16位,而biWidth和biHeight为32位。如果biHeight为负,则位图为从上到下存储。biBitCount还可以为16或32。biXPelsPerMeter和biYPelsPerMeter表示出图片的实际大小,一般设为0。biClrUsed是使用的颜色数,可以减少颜色表的项数,0表示全部都用了。对于16、24和32位位图,一般为0,如果不为0,表示颜色表项数,可以做为256色显卡的调色板。biClrImportant为0或biClrUsed表示全部颜色都重要,如果在这两个数中间,表示可以只用那个颜色渲染。biCompression可以是四个值:BI_RGB,BI_RLE8,BI_RLE4,或BI_BITFIELDS。对于4位或8位位图,它表示位图是否压缩,对于16或32位位图,表示是否用颜色掩码编码。1位和24位位图只能是BI_RGB,不压缩,8位还可以是BI_RLE8(Run-length encoding),4位可以是BI_RLE4,biHeight为负不能压缩。 16位与32位可以为BI_RGB或BI_BITFIELDS,涉及到像素值的位移,好麻烦,不写了。
扩展DIB颜色表结构体改为四元组(rgb): ,第四个字段总为0。
扩展DIB位图信息结构体:
还有DIB Version4 和 Version5的信息头结构体,分别是BITMAPV4HEADER和BITMAPV5HEADER,它们都是对BITMAPINFORHEADER的扩展。
DIB像素结构为4字节对齐,底行像素先存储。
函数
SetDIBitsToDevice(hdc,xDst,yDst,cxSrc,cySrc,xSrc,ySrc,yScan,cyScans,pBits,pInfo,fClrUse):将DIB的每个像素点显示到设备上,不进行拉伸,不受Map Mode影响,做什么变化也不会改变图片显示的方向,但可只显示部分。(xDst,yDst)是图片的左上角显示位置,(xSrc,ySrc)是要显示部分的左上角,对于BottomUp位图,(0,0)是DIB最后一行第一个点,TopDown位图(0,0)是DIB第一行第一个点。cxSrc和cySrc要显示的行数和列数,一般取图片长宽显示整个图片。从yScan开始,扫描cyScans行。pBits是DIB位图指针,pInfo是BITMAPINFO指针,指向文件头后面的内容在内存中的地址。fClrUse是DIB_RGB_COLORS或DIB_PAL_COLORS,DIB_RGB_COLORS指用DIB中Color Table中的值为颜色,用DIB_PAL_COLORS表示Color Table的值是调色板的索引。返回显示的行数。
StretchDIBits(hdc,xDst,yDst,cxDst,cyDst,xSrc,ySrc,cxSrc,cySrc,pBits,pInfo,fClrUse,dwROP):参数大部分和SetDIBitsToDevice相同。可以对位图进行拉伸、镜像,设备的Map Mode对位图的显示有完全的影响(大小和方向)
用SetDIBitsToDevice和StretchDIBits对显示时,要把位图颜色转化为设备颜色,性能不好,解决方法是把DIB转化为DDB。可以用SetDIBitsToDevice把DIB写到显示设备的兼容DC,或者用CreateDIBitmap函数更为简单。
CreateDIBitmap(hdc,pInfoHdr,fInit,pBits,pInfo,fClrUse):把DIB位图创建为DDB。返回HBITMAP。pInfoHdr与pInfo分别是BITMAPINFOHEADER和BITMAPINFO结构体指针。fInit为0或CBM_INIT,为0则不进行初始化,后面参数都是0。fCrlUse为DIB_RGB_COLORS或DIB_PAL_COLORS。hdc为0则创建单色DDB。
SetDIBits(hdc,hBitmap,yScan,cyScans,pBits,pInfo,fClrUse):如果CreateDIBitmap没有初始化位图,则用这个函数填充。只有当fClrUse为DIB_PAL_COLORS时才要用hdc。
GetDIBits(hdc,hBitmap,yScan,cyScans,pBits,pInfo,fClrUse):DDB转化为DIB。
CreateDIBSection(hdc,pInfo,fClrUse,ppBits,hSection,dwOffset):只有当fClrUse为DIB_RGB_COLORS(0)时hdc才有效。hSection与dwOffset为0,pInfo是BITMAPINFO结构体指针,ppBits是指向BYTE指针的指针,返回的*ppBits指各未初始化的位图,可以用ReadFile读取DIB像素来填充。*ppBits指向的内存由系统管理,当调用DeleteObject删除HBITMAP时会自动回收内存。hSection和dwOffset分别是文件映射句柄和位图像素在文件内的偏移量,用来初始化*ppBits,hSection可同CreateFileMapping获得,dwOffset必须为4的倍数,但DIB信息头与颜色表为4的倍数,文件头为14,所以后两个参数总是无效的。
CreateDIBSection与其他函数创建的DIB不同:
(1)调用BitBlt或StretchBlt时,DIB才转化为DDB。
(2)CreateDIBSection返回的位图句柄也可以选入兼容DC,用GDI函数在兼容DC上绘图也会修改*ppBits指向的DIB对应的像素,但在访问这些内存前要先调用GdiFlush函数。
(3)CreateDIBitmap返回的位图句柄和hdc的plane数和颜色组织一样,但CreateDIBSection就不同,它与BITMAPINFOHEADER字段的内容相同
(4)CreateDIBSection返回的HBITMAP可以用GetObject获取DIBSECTION结构体(GetObject(hBitmap,sizeof(DIBSECTION),&dibsection))。DIBSECTION的定义为 最后两个字段是CreateDIBSection最后的两个参数值。DIBSECTION没有颜色表指针,可用GetDIBColorTable函数获取。
显示的三种方法比较
SetDIBitsToDevice和StretchDIBits性能不好,如果显示小位图或绘制不频繁用这种方法。CreateDIBitmap和SetDIBits把DIB转化为DDB再用BitBlt和StretchBlt可提高效率,但DDB于DIB没有关联。在Windows NT中,用CreateDIBSection比SetDIBitsToDevice效率高,同时对DDB的修改也会改变DIB内存块。