windows程序设计学习笔记-设备无关位图

来源:互联网 发布:苹果id解锁软件 编辑:程序博客网 时间:2024/06/04 19:56

GIF,JPEG格式压缩了图像数据。DIB一般都不压缩。
Windows API直接支持DIB。
DIB提供了一个用来交换图像的文件格式。

Windows应用程序用到的位图一般作为DIB,存在可执行文件的只读资源中。
程序可把DIB文件除去开始的14字节,载入到一块连续内存。也可在内存创建DIB,然后存至文件。

DIB文件格式:

1.文件头
2.信息头
3.RGB颜色表[又时没有]
4.位图像素位

2,3,4称内存中紧凑格式的DIB。剪切板传输DIB时使用。

DIB文件头:
typedef struct tagBITMAPFILEHEADER
{
WORD bfType; // 文件签名,”BM”或0x4D42
DWORD bfSize; // 整个文件长度
WORD bfReserved1; // 0
WORD bfReserved2; // 0
DWORD bfOffBits; // 到位图像素位的位移
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;

DIB信息头
typedef struct tagBITMAPCOREHEADER
{
DWORD bcSize; // 结构大小,固定12字节
WORD bcWidth; // 以像素为单位的图像宽
WORD bcHeight; // 以像素为单位的图像高
WORD bcPlanes; // = 1
WORD bcBitCount; // 每个像素的位数1,4,8,24
} BITMAPCOREHEADER, FAR *LPBITMAPCOREHEADER, *PBITMAPCOREHEADER;

当像素位是1,4,8时,后面是颜色表。24后面不要颜色表。
DIB颜色表是一个数组。
DIB颜色表数组元素类型:
typedef struct tagRGBTRIPLE
{
BYTE rgbtBlue; // 蓝色值
BYTE rgbtGreen; // 绿色值
BYTE rgbtRed; // 红色值
} RGBTRIPLE, *PRGBTRIPLE, NEAR *NPRGBTRIPLE, FAR *LPRGBTRIPLE;

typedef struct tagBITMAPCOREINFO
{
BITMAPCOREHEADER bmciHeader;
RGBTRIPLE bmciColors[1];
} BITMAPCOREINFO, FAR *LPBITMAPCOREINFO, *PBITMAPCOREINFO;
这个结构用来同时包含 信息头和颜色表。
颜色表元素个数为2的像素位数 的次方。

后面数据就是像素位本身。

DIB从图像最下面一行开始,逐渐向上来存储图像。每一行的像素从左往右安排。
每一行所用的字节数必须是4的倍数。不够可以补。
RowLength = 4 * ((bmch.bcWidth * bmch.bcBitCount + 31) / 32);
所有像素占用的字节数:
RowLength * bmch.bcHeight.

对DIB像素部分数据解释。
以像素部分前3个字节为例。每个字节排开后,对应字节从7-0。0最低位,7最高位。
像素位为1时:
1的7-0,分别对应像素0-7在颜色表里的数据下标。
2的7-0,分别对应像素8-15在颜色表里的数据下标。
3的7-0,分别对应像素16-23在颜色表里的数据下标。

像素位为4时:
1的7-4表示像素0在颜色表里的数据下标。
1的3-0表示像素1在颜色表里的数据下标。

2的7-4表示像素2在颜色表里的数据下标。
2的3-0表示像素3在颜色表里的数据下标。

3的7-4表示像素4在颜色表里的数据下标。
3的3-0表示像素5在颜色表里的数据下标。

像素位为8时:
1的7-0表示像素0在颜色表里的数据下标。
2的7-0表示像素1在颜色表里的数据下标。
3的7-0表示像素2在颜色表里的数据下标。

像素位为24时:
1的7-0表示像素0的蓝色值。
2的7-0表示像素0的绿色值。
3的7-0表示像素0的红色值。

windows扩展的DIB格式。

扩展DIB文件头:
typedef struct tagBITMAPFILEHEADER
{
WORD bfType; // 文件签名,”BM”或0x4D42
DWORD bfSize; // 整个文件长度
WORD bfReserved1; // 0
WORD bfReserved2; // 0
DWORD bfOffBits; // 到位图像素位的位移
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;

扩展DIB信息头
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize; // 结构大小。固定为40.
LONG biWidth; // 以像素计的图像的宽度
LONG biHeight; // 以像素计的图像的高度
WORD biPlanes; // = 1
WORD biBitCount; // 每个像素的位数。1,4,8,16,24,32
DWORD biCompression; // 压缩编码
DWORD biSizeImage; // 图像的字节数
LONG biXPelsPerMeter; // 水平分辨率
LONG biYPelsPerMeter; // 垂直分辨率
DWORD biClrUsed; // 用到的颜色数。
DWORD biClrImportant; // 重要颜色的数目
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;

对1,4,8位的DIB。接在扩展DIB后面的是一个指明颜色的数组。
数组元素的结构是:
typedef struct tagRGBQUAD
{
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved; // 0
} RGBQUAD;

typedef struct tagBITMAPINFO
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO, FAR *LPBITMAPINFO, *PBITMAPINFO;
改结构包含了扩展的DIB信息头和扩展的颜色表数组。

biClrUsed在后面跟扩展颜色表时,用来指出颜色表中需要出现的元素个数。为0,表示2的像素位数的次方个数组都要出现。

对1,4,8,24的DIB像素位的组织和非扩展DIB中一样。

biCompression:
DIB位数:1,4,8,24
BI_RGB, BI_RLE8, BI_RLE4

行程长度编码:
1.1,该字段总是 BI_RGB
2.4,该字段为 BI_RGB或BI_RLE4.
3.8,该字段为 BI_RGB或BI_RLE8.
4.24,该字段总为 BI_RGB.
为BI_RGB像素位按 之前的DIB中那样存储。否则,像素位按行程长度编码来压缩。

行程长度编码:
DIB图像一行中存在多个连续的相同元素。对此段,记录重复次数和值。也能用于存储非矩形图像。

以biCompression为BI_RLE8为例:
字节1 字节2 字节3 字节4
00 00 一行的结尾
00 01 图像的结尾
00 02 dx dy 移动到(x+dx,y+dy)
00 03-FF 使用接下来n个像素。n为奇数时,后面再补一个0x00
01-FF 像素 重复像素n次

只要biCompression是BI_RLE4或BI_RLE8,biSizeImage字段存储以字节为单位的DIB像素数据的大小。

DIB位数:16,32
BI_RGB,BI_BITFIELDS。

该字段为 BI_RGB或BI_BITFIELDS。
16,32为 BI_RGB下,由像素值变量得到RGB,颜色遮罩略过。

int SetDIBitsToDevice
(
In HDC hdc,
In int xDst,
In int yDst,
In DWORD cxSrc,
In DWORD cySrc,
In int xSrc,
In int ySrc,
In UINT yScan,
In UINT cyScans,
In const VOID *pBits,
In const BITMAPINFO *pInfo,
In UINT fClrUse
);
在关联与目的设备环境的设备的指定矩形中设置像素。用来自于DIB,JPEG或PNG图片的数据。

hdc:设备环境句柄
XDst:目的矩形左上角X坐标。
YDst:目的矩形左上角Y坐标。
cxSrc:图片宽度。像素单位。
cySrc :图片高度。像素单位。
xSrc:图片左下角X坐标。像素单位。
ySrc:图片左下角Y坐标。像素单位。
yScan:图片中开始扫描行。扫描总是从图片的下面往上面扫描的。故对自下而上存的DIB,yScan从0-n.对自上而下存的DIB,yScan从n-0.
cyScans:lpvBits指向的数组内DIB扫描行的数目
pBits:指向颜色数据,存在一个字节位数组内。
pInfo:指向一个BITMAPINFO结构,其中包含了DIB文件的信息。
fClrUse:
1.DIB_PAL_COLORS:表示DIB里的颜色表将被由设备环境选中并实现的16位索引的逻辑调色板取代。
0.DIB_RGB_COLORS:颜色表包含RGB值。

返回值
成功,设置的扫描行行数。
失败,0或GDI_ERROR

In DWORD cxSrc,
In DWORD cySrc,
In int xSrc,
In int ySrc,

自下而上存储的DIB。内存结构和参数位置。
0-n行分别表示图形的n-0行。

                  xSrc                xSrc + cxSrc

ySrc

ySrc + cySrc

自上而下存储的DIB。内存结构和参数位置。
0-n行分别表示图形的0-n行
ySrc + cySrc

ySrc

                   xSrc                        xSrc + cxSrc

SetDIBitsToDevicez支持多次调用,每次设置若干扫描行,来实现DIB显示。多次调用其它参数不变,改变
In UINT yScan, // 从DIB存储角度的本次扫描开始行
In UINT cyScans, // 扫描行数
In const VOID *pBits, // 从DIB存储角度的本次扫描开始地址。
三个参数即可。

调用一次显示整个图像,yScan为0,cyScan为总行数。不用考虑存储顺序问题。

int StretchDIBits(
In HDC hdc,
In int XDest,
In int YDest,
In int nDestWidth,
In int nDestHeight,
In int XSrc,
In int YSrc,
In int nSrcWidth,
In int nSrcHeight,
In const VOID *lpBits,
In const BITMAPINFO *lpBitsInfo,
In UINT iUsage,
In DWORD dwRop
);

hdc:目的设备环境句柄
XDest:目标矩形左上角X坐标。逻辑单位。
YDest:目标矩形左上角Y坐标。逻辑单位。
nDestWidth:目标矩形宽。逻辑单位。
nDestHeight :目标矩形高。逻辑单位。
XSrc:图片里源矩形X坐标。像素单位。
YSrc:图片里源矩形Y坐标。像素单位。
nSrcWidth:图片里源矩形宽。像素单位。
nSrcHeight:图片里源矩形高。像素单位。
lpBits :指向图片像素位数组。
lpBitsInfo:指向包含DIB信息的BITMAPINFO
iUsage:
DIB_PAL_COLORS
DIB_RGB_COLORS
dwRop:光栅操作。指定源矩形中像素和目的设备环境像素和目的设备环境当前画刷结合方式。

返回值:
被拷贝的扫描行数目
0:没有扫描行被拷贝或失败
GDI_ERROR:源图片不被支持。

剪切板使用举例:

            HGLOBAL hGlobal = GlobalAlloc (GHND | GMEM_SHARE, pbmfh->bfSize -                                        sizeof (BITMAPFILEHEADER)) ;               pGlobal = GlobalLock (hGlobal) ;               CopyMemory (pGlobal, (BYTE *) pbmfh + sizeof (BITMAPFILEHEADER),                           pbmfh->bfSize - sizeof (BITMAPFILEHEADER)) ;               GlobalUnlock (hGlobal) ;               OpenClipboard (hwnd) ;               EmptyClipboard () ;               SetClipboardData (CF_DIB, hGlobal) ;               CloseClipboard () ;              OpenClipboard (hwnd) ;               hGlobal = GetClipboardData (CF_DIB) ;               pGlobal = GlobalLock (hGlobal) ;               if (pGlobal)               {                    pGlobal  // 指向你之前放入的数据,可以从指向的地方把数据拷贝出来               }               GlobalUnlock (hGlobal) ;               CloseClipboard () ;

DDB的API速度快于DIB,DDB支持选入位图后在其上画图。

DIB和DDB的相互转化:

从DIB到DDB

方法1:
1.1.BOOL CreateCompatibleBitmap(
CDC* pDC,
int nWidth,
int nHeight
);
创建设备兼容位图。
1.2.位图选入内存设备环境
1.3.利用SetDIBitsToDevice在内存设备环境上绘图。

使位图和DIB有相同图像。但位图是设备兼容的。

方法2:
2.1.HBITMAP CreateDIBitmap(
In HDC hdc,
In const BITMAPINFOHEADER *lpbmih,
In DWORD fdwInit,
In const VOID *lpbInit,
In const BITMAPINFO *lpbmi,
In UINT fuUsage
);

从一个设备无关位图中创建一个设备相关位图。

从DDB到DIB

int GetDIBits(
In HDC hdc,
In HBITMAP hbmp,
In UINT uStartScan,
In UINT cScanLines,
Out LPVOID lpvBits,
Inout LPBITMAPINFO lpbi,
In UINT uUsage
);

接收指定的兼容位图的位然后按指定的格式把他们拷贝到一个DIB缓冲
hdc:设备环境的句柄
hbmp:位图句柄。位图需要是设备兼容位图。
uStartScan:开始扫描行
cScanLines:扫描行数目
lpvBits :指向一个接收位图数据的缓冲。
lpbi :指向一个BITMAPINfO结构,来指定期望得到的DIB数据的格式。
uUsage:
DIB_PAL_COLORS
DIB_RGB_COLORS

如果lpvBits非NULL且执行成功,返回值是拷贝的扫描行数目。
如果lpvBits为NULL且执行成功,返回值非0.
执行失败,返回0
ERROR_INVALID_PARAMETER:参数无效

HBITMAP CreateDIBSection(
In HDC hdc,
In const BITMAPINFO *pbmi,
In UINT iUsage,
Out VOID **ppvBits,
In HANDLE hSection,
In DWORD dwOffset
);

创建一个DIB,应用可以直接写。
函数给你一个指针,指向位图位值地址。
你可提供一个指向文件映射对象句柄,函数将用来创建位图 或这 你能让系统为位图分配内存。

hdc:设备环境句柄
pbmi:指向BITMAPINFO结构,指定DIB属性。
iUsage:
DIB_PAL_COLORS
DIB_RGB_COLORS
ppvBits :指向一个变量,接受DIB位值地址。
hSection:文件映射对象句柄 ,函数用来创建DIB。可为NULL。
dwOffset:hSection不为NULL时,有意义。

返回值:
成功,新创建DIB的句柄。
失败,NULL
ERROR_INVALID_PARAMETER:参数无效

pvBits:指向的内存区域由系统管理。用DeleteObject删除这个位图时,内存会被自动释放。

用于显示DIB的三种方式:
1.SetDIBitsToDevice或StretchDIBits直接显示。
2.CreateDIBitmap或SetDIBits把DIB转成DDB,用BitBlt或StretchBlt显示。
3.CreateDIBSection创建DIB区块,允许你通过pBits手动修改像素位。
CreateDIBSection返回的位图可以选入与设备兼容的内存设备环境。

返回的位图还能用
GetObject(hBitmap, sizeof(DIBSECTION), &dibsection);

在把此位图选入内存设备环境后,还可以用
GetDIBColorTable(hdcMem, uFirstIndex, uNumEntries, &rgb);

文件映射对象让你可以把一个文件当作已经在内存一样。好处是文件过大时可减少内存需求,但速度会变慢。

0 0