BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成。
一.理论基础
1.
typedef struct tagBITMAP
{
LONG bmType;
LONG bmWidth;
LONG bmHeight;
LONG bmWidthBytes;
WORD bmPlanes;
WORD bmBitsPixel;
LPVOID bmBits;
} BITMAP;
该结构定义了一幅位图的高、宽、颜色格式以及位值。
bmType 必须为0;
bmWidth,bmHeight 位图宽高(单位:象素);
bmWidthBytes 每一光栅行的字节数,必须为偶数,因为GDI假定位图的位数组是字(16bit)对齐;
bmPlanes 位图的颜色平面数;
bmBitsPixel 指定每个象素需要多少位;
bmBits 指向位图位值的地址,必须是一个指向字符数组的指针。
2.
typedef struct tagBITMAPCOREHEADER
{
DWORD bcSize; /* used to get to color table */
WORD bcWidth;
WORD bcHeight;
WORD bcPlanes;
WORD bcBitCount;
} BITMAPCOREHEADER;
该结构包含了设备无关位图的大小和颜色格式的信息。
bcSize 指定该结构本身所需要的字节数;
bcWidth,bcHeight 位图的宽高(单位:象素);
bcPlanes 指定目标设备的平面数(必须为1);
bcBitCount 指定每一个象素的位数,此值必须为1、4、8 或24。(我们这里8色,则必须设置该数字为4)
3.
typedef struct tagRGBTRIPLE
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} RGBTRIPLE;
typedef struct _BITMAPCOREINFO
{
BITMAPCOREHEADER bmciHeader;
RGBTRIPLE bmciColor[1];
} BITMAPCOREINFO;
该结构完整地定义了设备无关位图的大小和颜色信息。
bmciHeader 指定了一个数据结构,它包含了设备无关位图的大小和颜色信息;
bmciColor[1] 指定了一个结构,它定义了位图中的颜色。
一个应用程序可以利用bcSize成员中的信息来定位BITMAPCOREINFO结构中的颜色表,具体方法如下:
pColor = ((LPBYTE)pBitmapCoreInfo + (WORD)(pBitmapCoreInfo->bmciHeader.bcSize))
4.
typedef struct tagBITMAPFILEHEADER
{
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
该结构包含了设备无关位图文件的类型、大小、布局等信息。
bfType 指定文件类型,必须为BM;
bfSize 以字节为单位指定文件大小;
bfReserved1 必须为0;
bfReserved2 必须为0;
bfOffBits 指定位图文件中实际位图偏移于BITMAPFILEHEADER的字节数。
5.
typedef struct tagRGBQUAD
{
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
} RGBQUAD;
typedef struct tagBITMAPINFO
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO;
该结构定义了设备无关位图的大小和颜色等信息。
bmiHeader 指定了一个结构,该结构包含了设备无关位图的大小和颜色格式等信息;
bmiColors[1] 指定了一个结构,该结构定义了位图中的颜色。
6.
typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER
该结构包含了设备无关位图的大小和颜色信息。
biSize 该结构所需的字节数;
biWidth, biHeight 位图宽高;
biPlanes 目标设备平面数,必须为1;
biBItCount 指定每个象素的位数,必须为1、4、8、或24;
biCompression 指定位图的压缩类型,必须为BI_RGB,BI_RGB8,或BI_RLE4;
biSizeImage 图像的字节大小;
biXPelsPerMeter, biYPelsPerMeter 位图的目标设备的水平、垂直分辨率(每米象素数);
biClrUsed 指定位图所实际使用的颜色表中的颜色数;
biClrImportant 指定显示位图中重要的颜色索引数,0:所有颜色均是重要的。
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
二、实际应用
1.文件结构
位图文件数据存储结构(字节单位):
前14字节(BITMAPFILEHEADER 文件头数据结构)
详细结构参考上面文档。
之后40字节(BITMAPINFOHEADER 位图信息头数据结构)
详细结构参考上面文档。
之后 调色板数据
只有小于等于8位象素才需要调色板,
最后,位图数据
大小:象素宽 × 象素高 × 每象素字节数
注意:位图文件中的颜色格式与平时的颜色组织格式稍有不同,它的颜色格式是
蓝色 blue
绿色 green
红色 red
平时的是 Red,Greed,Blue
2. 例子附带说明
关于位图文件内部数据是怎么组织的?关键是看参数biBitCount的值,该参数只有5个可选值1、4、8、24、32。根据它们的选值情况,文件有3种组织格式,下面分别用例子说明:
公共部分:文件头
前面14个字节,
typedef struct tagBITMAPFILEHEADER
{
WORD bfType; //必填“BM”或“0x4D 42”
DWORD bfSize; //必填 文件总的字节大小
WORD bfReserved1;//必填 0
WORD bfReserved2;//必填 0
DWORD bfOffBits; //必填,象素值开始位置到文件头位置的偏移量
} BITMAPFILEHEADER;
接着40个字节,
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize; //必填 0x28
LONG biWidth; //必填 象素宽
LONG biHeight; //必填 象素高
WORD biPlanes; //必填 1
WORD biBitCount; //必填 1、4、8、24、32之一,该值很重要!
DWORD biCompression;//必填BI_RGB,BI_RGB8,BI_RLE4之一,一般是BI_RGB
DWORD biSizeImage; //可选填,值为象素信息的字节总数
LONG biXPelsPerMeter;//可选填,一般为C4 0E 00 00,也可填0
LONG biYPelsPerMeter; //可选填,同上
DWORD biClrUsed; //必填,一般为0,
DWORD biClrImportant;//必填,一般为0
} BITMAPINFOHEADER
不同的部分:象素值
根据biBitCount参数有以下3种情况
<!--[if !supportLists]-->(1) <!--[endif]-->有调色板(biBitCount参数值为1、4、8)
此时位图文件先跟一段调色板颜色数据,再跟象素的颜色索引信息数据;
<!--[if !supportLists]-->(2) <!--[endif]-->无调色板(biBitCount参数值为24)
此时直接跟一段象素数据,每个象素由3个字节表示颜色值,顺序BGR;
<!--[if !supportLists]-->(3) <!--[endif]-->无调色板(biBitCount参数值为32)
此时直接跟一段象素数据,每个象素由4个字节表示颜色值,顺序BGR;
例1;1位象素单色4×4位图,假设第1、3象素为黑色,其他都为白色,那么有下面的数据来表示该位图的象素颜色值
00 00 00 00 FF FF FF 00; 50 00 00 00 F0 00 00 00 F0 00 00 00 F0 00 00 00.
说明:前面8个字节,是调色板的值,单色只有黑色和白色两种,它们的RGB表示就是前面的8个字节。RGB(0,0,0)为黑色,RGB(255,255,255)为白色,
50 00 00 00表示第一行位图象素,这里只有前4位有效,其他位都是补位而已。5的二进制就是0101,它对应第一行的四个象素的颜色索引“黑白黑白”;
F0 00 00 00表示第二行的位图象素,这里也是前4位有效,F的二进制是1111,正好对应颜色索引“白白白白”;
其他行的象素颜色一样表示法。
注:这里单色,所以参数biBitCount为1,即1位表示一个象素,所以4×4的每行就只有4位来表示象素颜色就够了,但是,系统规定必须32位对齐,所以需要28位0来来补足。故这里的每行都用4个字节来表示,只是后面28位没有实际用处而已。
注意:每个调色板中的一种颜色,必须用4个字节表示(RGB绝对值)
注意:关于象素每行补位算法,到底要补多少位,这可以不用操心,用算法
int i = ((Bitmap.bmWidth *wBitCount+31)/32)*4*Bitmap.bmHeight 得到的i就是: 描述位图象素颜色总的要用到的字节数。该字节数减去该行象素的字节数,就是补位的字节数。
调色板的颜色个数为2的biBitCount次幂,
例2:4位象素8色的4×4位图,假设第一行第一象素为绿色,第三象素为红色,第二象素为蓝色,底为黑色,则有下面的数据来表示该位图文件的颜色值
RGBQUAD pallete[16] = { (0x0, 0x0, 0x0, 0x0), (0xFF, 0xFF, 0xFF, 0x0), (0xFF,0x0,0x0,0x0), (0x0,0xFF,0x0,0x0),( 0x0,0x0,0xFF,0x0),( 0xFF,0xFF,0x0,0x0),( 0xFF,0x0,0xFF,0x0),
(0x0,0xFF,0xFF,0x0),( 0xFF,0x80,0x0,0x0),( 0xFF,0x0,0x80,0x0),( 0xFF,0x80,0x80,0x0),
(0xFF,0xFF,0x80,0x0),( 0x80,0x80,0x80,0x0),( 0x80,0x0,0x0,0x0),( 0x,0x80,0x0,0x0),
(0x0,0x0,0x80,0x0)};
这是调色板颜色值,后面要跟各个象素的颜色索引值,它们共同组成象素颜色值的表述
32 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00
第一行“32 40 00 00”分别表示“绿蓝红黑”后16位为补位;
其他行一样的理解。
例3:24位象素彩色的4×4位图,假设第一行第一象素为绿色,第三象素为红色,第二象素为蓝色,底为白色,则有下面的数据来表示该位图文件的颜色值
00 FF 00 FF 00 00 00 00 FF FF FF FF 00(标志换行)
FF FF FF FF FF FF FF FF FF FF FF FF 00
FF FF FF FF FF FF FF FF FF FF FF FF 00
FF FF FF FF FF FF FF FF FF FF FF FF 00
注意:24位象素的位图文件没有调色板,但是,它的每个象素也不是用4字节表示,而是用3字节表示,即没有那个颜色结构的保留字节。但是,这样就会出现每行字节不能16位对齐的问题,所以每行完了必须要有个行结束字节“00”,
例4:32位象素真彩色的4×4位图,假设第一行第一象素为绿色,第三象素为红色,第二象素为蓝色,底为白色,则有下面的数据来表示该位图文件的颜色值
00 FF 00 00 FF 00 00 00 00 00 FF 00 FF FF FF 00
FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF FF 00
FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF FF 00
FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF FF 00
32位象素的位图,也没有调色板,但是它的颜色值是用4字节来表示的,除了RGB值外,还有一个保留值,始终为0。
这里的例子没有列举8位象素64色的位图,它的文件组织格式参看4位象素16色的例子。
CPaintDC dc(this); // device context for painting CRect clientRect(0,0,0,0); GetDlgItem(IDC_WAVE_UI_BMP)->GetWindowRect(&clientRect);//显示位图到控件上 ScreenToClient(&clientRect);
位图显示终于做出来了,可以随着装载容器的大小变换而始终完全填充。用的函数是
StretchDIBits(dc.m_hDC, clientRect.left, clientRect.top, clientRect.Width(), clientRect.Height(),
0, 0, m_BmpInfoHeader.biWidth, m_BmpInfoHeader.biHeight, m_pRGBdatabuf, (LPBITMAPINFO)&m_BmpInfoHeader, DIB_RGB_COLORS, SRCCOPY);
其参数分别为:
:目标设备环境,Handle to the destination device context
:目标容器(显示位图的控件)起始 X 坐标值
:目标容器(显示位图的控件)起始 Y 坐标值
:目标容器(显示位图的控件)宽
:目标容器(显示位图的控件)高 以上四个值都为逻辑单位
:源位图的起始 X 坐标值
:源位图的起始 Y 坐标值
:源位图的宽
:源位图的高 以上四个值都为象素单位
:象素RGB值数组的起始地址
:源位图的位图信息指针
:位图象素的颜色显示模式 ,只有DIB_RGB_COLORS 和 DIB_PAL_COLORS两种,后者为有调色板的情况。
:源位图与目标位图的操作模式。一般为 SRCCOPY