Keep on going, never give up.

BMP位图文件格式详解及编程建议

BMP文件渊源流长,虽然对JPG、PNG等格式图像文件来说,确实有点土,但是毕竟BMP文件格式相对简单,容易理解,至于BMP众多的位图格式也不能责怪微软,主要是早期谁也没料到图片技术会发展的这么快,而且每次升级还要兼容,所以只能如此了(有点麻烦但并不复杂)。天缘撰写本文以便留档和各位编程爱好者参考。

BMP位图文件的结构主要由:BMP文件头、位图信息头、颜色表和图形数据四个部分组成,对于24位、32位则没有色彩表字段,低位图则存在色彩索引表。

一、BMP的文件头结构

BMP文件头数据结构包含有BMP文件类型标志、文件大小和位图数据的起始位置等信息。

其结构定义如下:

typedef strUCt tagBITMAPFILEHEADER

{

WORD bfType;

DWORD bfSize;

WORD bfReserved1; // 保留字,必须为0

WORD bfReserved2; // 保留字,必须为0

DWORD bfOffBits;

} BITMAPFILEHEADER;

bfType——为位图文件类型,必须为BM,转化为十六进制码就是0x4d42(小端约定,关于大端和小端概念请参考稍后的天缘文章)

bfSize——位图文件的大小,以字节为单位,表示整个bmp文件的大小,包括2个头段和位图数据区,计算方法如下:

sizeof(BITMAPFILEHEADER)+ sizeof(BITMAPINFOHEADER)+ (biWidth* biBitCount+31)/8*biHeight

可能很多网友对公式中的后半段很疑惑,为什么那样计算数据区的大小,这是因为Windows还规定图像文件中一个扫描行所占的字节数必须是4的倍数,不足部分要以0填充,所以数据区的大小不能使用简单的(biWidth*biBitCount*biHeight)/8计算总字节数,而应当折算每行的BIT数,分子中的加31(因为4字节补齐就是32位补齐)就是为了防止一个扫描行多一位或少一位而做的进位(+31)取整(/8)操作。

bfOffBits—— 位图数据的起始位置,也就是数据区的起始位置,基点是位图数据区相对文件头部的偏移量,单位为字节。

二、BMP位图信息头结构

BMP位图信息头结构主要用于说明位图的尺寸、压缩类型等重要信息。其结构如下:

typedef struct tagBITMAPINFOHEADER{

DWORD biSize; //本结构所占字节数,实际上该结构占用40个字节,但Windows每次还是需要您亲自添上

LONG biWidth; //位图的宽度,单位为像素

LONG biHeight; //位图的高度,单位为像素

WORD biPlanes; //目标设备的平面数,约定必须为1

WORD biBitCount//每个像素所需的位数,必须是1(双色)、 4(16色)、8(256色)、24(真彩色)或32(32位真彩)之一

DWORD biCompression; //位图压缩类型,必须是0(不压缩)、1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一

DWORD biSizeImage; //位图的大小,以字节为单位,对于BI_RGB必须设置为0,对于压缩文件请参考MSDN

LONG biXPelsPerMeter; //水平分辨率,每米像素数,一般不用关心,设为0

LONG biYPelsPerMeter; //垂直分辨率,每米像素数,一般不用关心,设为0

DWORD biClrUsed;//位图实际使用的颜色表中的颜色数,一般不用关心,设为0

DWORD biClrImportant;//位图显示过程中重要的颜色数,一般不用关心,设为0

} BITMAPINFOHEADER;该结构占据40个字节。

三、BMP的调色板结构,或叫色彩表

这一项在网络上很多文章没有提及,或只说到调色板的概念,主要是因为现在使用颜色表的BMP(24真彩以下的图片很少的缘故),这里介绍一下,颜色表表示BMP文件的DIB(device-independent bitmap)尺寸和颜色信息。结构定义如下:

typedef struct _BITMAPCOREINFO {

BITMAPCOREHEADER bmciHeader; //见下面的结构定义

RGBTRIPLE bmciColors[1]; //见下面的结构定义

} BITMAPCOREINFO;

BITMAPCOREHEADER的定义如下:

typedef struct tagBITMAPCOREHEADER { // bmch

DWORD bcSize; //表示本结构的占用字节数

WORD bcWidth; //位图的宽度

WORD bcHeight; //位图的高度

WORD bcPlanes; //设备平面数,设为1

WORD bcBitCount; //每像素位数,比如为1、4、8、24,实际上最后的24似乎没用,当然也可以使用程序约定使用。

} BITMAPCOREHEADER

RGBTRIPLE的结构定义如下:

typedef struct tagRGBTRIPLE { // rgbt

BYTE rgbtBlue; //蓝色

BYTE rgbtGreen; //绿色

BYTE rgbtRed; //红色

} RGBTRIPLE

四、BMP的位图数据区

提到位图数据区,肯定要涉及到颜色表的概念,颜色表用于说明位图中的颜色,按照位图的像素划分,每一个像素用一个RGBQUAD结构表示一种颜色。RGBQUAD结构的定义如下:

typedef struct tagRGBQUAD {

BYTE rgbBlue;//蓝色

BYTE rgbGreen; // 绿色

BYTE rgbRed; // 红色

BYTE rgbReserved;// 保留

} RGBQUAD;

根据天缘的认识,该结构只是在程序处理时候用得着,随意你怎么解释都可以,只要不把RGB颜色倒反即可。位图信息头和颜色表组成位图信息区,BITMAPINFO结构定义如下:

typedef struct tagBITMAPINFO {

BITMAPINFOHEADER bmiHeader; // 位图信息头

RGBQUAD bmiColors[1]; // 颜色表

} BITMAPINFO;

结构体里头的RGBQUAD项就是真实的颜色表,大小根据实际情况确定。

颜色表的结构来也很简单,就是使用RGB三色调和最终的位图颜色信息。至于最终实际使用多少字节的RGBQUAD数据还需要由biBitCount决定,所以,并不是上述结构中使用BYTE来定义就表示一定占用四字节。天缘说明如下:

1、当biBitCount=1时,8个像素占1个字节,每个像素智能用一BIT来表示,颜色只能有两种1或0,也就是双色,具体颜色需查色彩表。

2、当biBitCount=4时,2个像素占1个字节,每个像素占半个字节(4位),可能颜色有2^4=16种,也就是16色,具体颜色需查色彩表。

3、当biBitCount=8时,1个像素占1个字节,可能颜色有2^8=256种,也就是256色,具体颜色需查色彩表。

4、当biBitCount=16时,1个像素占2个字节,可能颜色有2^16=65536种,也就是64K,具体颜色需查色彩表。

5、当biBitCount=24时,1个像素占3个字节,可能颜色有2^24=16777216,这么多颜色如果是写色彩表就需要占用至少16M,全宇宙肯定不同意的,所以干脆就拿每个字节表示一种颜色,正好三个字节RGB,“非常6+1”。

6、当biBitCount=32时,1个像素占4个字节,这在网上很多文章中都没有提到,只说到24位,32位真彩就是原来的rgbReserved使用上,作为透明度标示。理解方法同24位,加上Reserved保留的透明度,具体颜色天缘暂时还算不出来。

编程建议(面向数据处理):

1、BMP文件的读取提取到二维数组,对于使用C/C++、VC++的朋友,有现成DIB派生类可以参考,GOOGLE一下即可。

2、对于BMP文件的普通读取、绘图有很多现成的系统函数可供调用,天缘不再细说,比如CreateDIBitmap、CreateCompatibleDC、BitBlt、StretchBlt等等。

2、BMP文件的写操作只需要按照上述的BMP文件格式,把BMP文件头、信息表及位图数据区按照顺序写成BMP文件即可。

各位网友

——凡是喜爱编程的网友,敬请留言交流,同道知音何处可觅?

相关评论(0):  

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

订阅博客

最新文章

本站采用创作共用版权协议, 要求署名、非商业用途和保持一致. 转载也必须遵循“署名-非商业用途-保持一致”的创作共用协议. 返回顶部
Copyright@2005-2016 Metsky.com, All rights Reserved.