BMP图像格式详解.docx
- 文档编号:17778543
- 上传时间:2023-08-03
- 格式:DOCX
- 页数:24
- 大小:26.52KB
BMP图像格式详解.docx
《BMP图像格式详解.docx》由会员分享,可在线阅读,更多相关《BMP图像格式详解.docx(24页珍藏版)》请在冰点文库上搜索。
BMP图像格式详解
BMP格式图像文件详析
首先请注意所有的数值在存储上都是按“高位放高位、低位放低位的原则”,如12345678h放在存储器中就是78563412)。
下图是导出来的开机动画的第一张图加上文件头后的16进制数据,以此为例进行分析。
T408中的图像有点怪,图像是在电脑上看是垂直翻转的。
在分析中为了简化叙述,以一个字(两个字节为单位,如424D就是一个字)为序号单位进行,“h”表示是16进制数。
424D4690000000000000460000002800000080000000900000000100*10000300000000900000A00F0000A00F00000000000000000000*00F80000E00700001F00000000000000*02F184F104F184F184F106F284F106F204F286F206F286F286F2
......
BMP文件可分为四个部分:
位图文件头、位图信息头、彩色板、图像数据阵列,在上图中已用*分隔。
一、图像文件头
1)1:
图像文件头。
424Dh=’BM’,表示是Windows支持的BMP格式。
2)2-3:
整个文件大小。
46900000,为00009046h=36934。
3)4-5:
保留,必须设置为0。
4)6-7:
从文件开始到位图数据之间的偏移量。
46000000,为00000046h=70,上面的文件头就是35字=70字节。
5)8-9:
位图图信息头长度。
6)10-11:
位图宽度,以像素为单位。
80000000,为00000080h=128。
7)12-13:
位图高度,以像素为单位。
90000000,为00000090h=144。
8)14:
位图的位面数,该值总是1。
0100,为0001h=1。
二、位图信息头
9)15:
每个像素的位数。
有1(单色),4(16色),8(256色),16(64K色,高彩色),24(16M色,真彩色),32(4096M色,增强型真彩色)。
T408支持的是16位格式。
1000为0010h=16。
10)16-17:
压缩说明:
有0(不压缩),1(RLE8,8位RLE压缩),2(RLE4,4位RLE压缩,3(Bitfields,位域存放)。
RLE简单地说是采用像素数+像素值的方式进行压缩。
T408采用的是位域存放方式,用两个字节表示一个像素,位域分配为r5b6g5。
图中03000000为00000003h=3。
11)18-19:
用字节数表示的位图数据的大小,该数必须是4的倍数,数值上等于位图宽度×位图高度×每个像素位数。
00900000为00009000h=80×90×2h=36864。
12)20-21:
用象素/米表示的水平分辨率。
A00F0000为00000FA0h=4000。
13)22-23:
用象素/米表示的垂直分辨率。
A00F0000为00000FA0h=4000。
14)24-25:
位图使用的颜色索引数。
设为0的话,则说明使用所有调色板项。
15)26-27:
对图象显示有重要影响的颜色索引的数目。
如果是0,表示都重要。
三、彩色板
16)28-35:
彩色板规范。
对于调色板中的每个表项,用下述方法来描述RGB的值:
1字节用于蓝色分量
1字节用于绿色分量
1字节用于红色分量
1字节用于填充符(设置为0)
对于24-位真彩色图像就不使用彩色表,因为位图中的RGB值就代表了每个象素的颜色。
但是16位r5g6b5位域彩色图像需要彩色表,看前面的图,与上面的解释不太对得上,应以下面的解释为准。
图中彩色板为00F80000E00700001F00000000000000,其中:
00FB0000为FB00h=1111100000000000(二进制),是红色分量的掩码。
E0070000为07E0h=0000011111100000(二进制),是绿色分量的掩码。
1F000000为001Fh=0000000000011111(二进制),是红色分量的掩码。
00000000总设置为0。
将掩码跟像素值进行“与”运算再进行移位操作就可以得到各色分量值。
看看掩码,就可以明白事实上在每个像素值的两个字节16位中,按从高到低取5、6、5位分别就是r、g、b分量值。
取出分量值后把r、g、b值分别乘以8、4、8就可以补齐第个分量为一个字节,再把这三个字节按rgb组合,放入存储器(同样要反序),就可以转换为24位标准BMP格式了。
四、图像数据阵列
17)17-...:
每两个字节表示一个像素。
阵列中的第一个字节表示位图左下角的象素,而最后一个字节表示位图右上角的象素。
按照前述r5g6b5彩色板规范,我们对图像最左下角手机上图像的的像素在24位模式中的rgb值进行推算(由于垂直翻转,这个像素在手机上看来实际上在左上角):
02F1为F102h
r=(F102ANDFB00)/800×8h=F0h=240
g=(F102AND07E0)/20×4h=20h=32
b=(F102AND001F)×8h=10h=16
rgb=F02010h,放在存储器中为1020F0h。
在Photoshop中设一下颜色,rgb取240、32、16可以看到是近红色。
将手机中图像数据复制出来,加上前图中的文件头数据,只需要把6)、7)项位图宽、高设好就可以用ACDSEE进行查看了。
但是如果要用其他的程序进行处理,其他项目一般也需要正确设置。
按照这样的原则,可以写一个简单的程序把一幅24位BMP图像转换为手机支持的16位r5g6b5图像,然后写进AXF,刷机后就可以在手机上看到自己做的6万色真彩图了。
目前52和兰色可能都在开发这样的程序,有兴趣的朋友不妨先自己动手做几张图片。
//*******************************************BYRALF
最近正在着手开发一个图片库,也就是实现对常见图片格式的度写操作。
作为总结与积累,我会把这些图片格式以及加载的实现写在我的Blog上。
说到图片,位图(Bitmap)当然是最简单的,它Windows显示图片的基本格式,其文件扩展名为*.BMP。
在Windows下,任何各式的图片文件(包括视频播放)都要转化为位图个时候才能显示出来,各种格式的图片文件也都是在位图格式的基础上采用不同的压缩算法生成的(Flash中使用了适量图,是按相同颜色区域存储的)。
一、下面我们来看看位图文件(*.BMP)的格式。
位图文件主要分为如下3个部分:
块名称
对应Windows结构体定义
大小(Byte)
文件信息头
BITMAPFILEHEADER
14
位图信息头
BITMAPINFOHEADER
40
RGB颜色阵列
BYTE*
由图像长宽尺寸决定
1、文件信息头BITMAPFILEHEADER
结构体定义如下:
typedefstructtagBITMAPFILEHEADER{/*bmfh*/
UINTbfType;
DWORDbfSize;
UINTbfReserved1;
UINTbfReserved2;
DWORDbfOffBits;
}BITMAPFILEHEADER;
其中:
bfType
说明文件的类型,该值必需是0x4D42,也就是字符'BM'。
bfSize
说明该位图文件的大小,用字节为单位
bfReserved1
保留,必须设置为0
bfReserved2
保留,必须设置为0
bfOffBits
说明从文件头开始到实际的图象数据之间的字节的偏移量。
这个参数是非常有用的,因为位图信息头和调色板的长度会根据不同情况而变化,所以你可以用这个偏移值迅速的从文件中读取到位数据。
2、位图信息头BITMAPINFOHEADER
结构体定义如下:
typedefstructtagBITMAPINFOHEADER{/*bmih*/
DWORDbiSize;
LONGbiWidth;
LONGbiHeight;
WORDbiPlanes;
WORDbiBitCount;
DWORDbiCompression;
DWORDbiSizeImage;
LONGbiXPelsPerMeter;
LONGbiYPelsPerMeter;
DWORDbiClrUsed;
DWORDbiClrImportant;
}BITMAPINFOHEADER;
其中:
biSize
说明BITMAPINFOHEADER结构所需要的字数。
biWidth
说明图象的宽度,以象素为单位。
biHeight
说明图象的高度,以象素为单位。
注:
这个值除了用于描述图像的高度之外,它还有另一个用处,就是指明该图像是倒向的位图,还是正向的位图。
如果该值是一个正数,说明图像是倒向的,如果该值是一个负数,则说明图像是正向的。
大多数的BMP文件都是倒向的位图,也就是时,高度值是一个正数。
biPlanes
为目标设备说明位面数,其值将总是被设为1。
biBitCount
说明比特数/象素,其值为1、4、8、16、24、或32。
但是由于我们平时用到的图像绝大部分是24位和32位的,所以我们讨论这两类图像。
biCompression
说明图象数据压缩的类型,同样我们只讨论没有压缩的类型:
BI_RGB。
biSizeImage
说明图象的大小,以字节为单位。
当用BI_RGB格式时,可设置为0。
biXPelsPerMeter
说明水平分辨率,用象素/米表示。
biYPelsPerMeter
说明垂直分辨率,用象素/米表示。
biClrUsed
说明位图实际使用的彩色表中的颜色索引数(设为0的话,则说明使用所有调色板项)。
biClrImportant
说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。
3、RGB颜色阵列
有关RGB三色空间我想大家都很熟悉,这里我想说的是在Windows下,RGB颜色阵列存储的格式其实BGR。
也就是说,对于24位的RGB位图像素数据格式是:
蓝色B值
绿色G值
红色R值
对于32位的RGB位图像素数据格式是:
蓝色B值
绿色G值
红色R值
透明通道A值
透明通道也称Alpha通道,该值是该像素点的透明属性,取值在0(全透明)到255(不透明)之间。
对于24位的图像来说,因为没有Alpha通道,故整个图像都不透明。
二、搞清了文件格式,下一步我们要实现加载。
加载文件的目的是要得到图片属性,以及RGB数据,然后可以将其绘制在DC上(GDI),或是生成纹理对象(3D:
OpenGL/Direct3D)。
这两种用途在数据处理上有点区别,我们主要按前一种用法讲,在和3D有不同的地方,我们再提出来。
1、加载文件头
//Loadthefileheader
BITMAPFILEHEADERheader;
memset(&header,0,sizeof(header));
inf.read((char*)&header,sizeof(header));
if(header.bfType!
=0x4D42)
returnfalse;
这个很简单,没有什么好说的。
2、加载位图信息头
//Loadtheimageinformationheader
BITMAPINFOHEADERinfoheader;
memset(&infoheader,0,sizeof(infoheader));
inf.read((char*)&infoheader,sizeof(infoheader));
m_iImageWidth=infoheader.biWidth;
m_iImageHeight=infoheader.biHeight;
m_iBitsPerPixel=infoheader.biBitCount;
这里我们得到了3各重要的图形属性:
宽,高,以及每个像素颜色所占用的位数。
3、行对齐
由于Windows在进行行扫描的时候最小的单位为4个字节,所以当
图片宽X每个像素的字节数!
=4的整数倍
时要在每行的后面补上缺少的字节,以0填充(一般来说当图像宽度为2的幂时不需要对齐)。
位图文件里的数据在写入的时候已经进行了行对齐,也就是说加载的时候不需要再做行对齐。
但是这样一来图片数据的长度就不是:
宽X高X每个像素的字节数了,我们需要通过下面的方法计算正确的数据长度:
//Calculatetheimagedatasize
intiLineByteCnt=(((m_iImageWidth*m_iBitsPerPixel)+31)>>5)<<2;
m_iImageDataSize=iLineByteCnt*m_iImageHeight;
4、加载图片数据
对于24位和32位的位图文件,位图数据的偏移量为sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER),也就是说现在我们可以直接读取图像数据了。
if(m_pImageData)delete[]m_pImageData;
m_pImageData=newunsignedchar[m_iImageDataSize];
inf.read((char*)m_pImageData,m_iImageDataSize);
如果你足够细心,就会发现内存m_pImageData里的数据的确是BGR格式,可以用个纯蓝色或者是纯红色的图片测试一下。
5、绘制
好了,数据和属性我们都有了,现在就可以拿来随便用了,就和吃馒头一样,爱粘白糖粘白糖,爱粘红糖粘红糖。
下面是我的GDI绘制代码,仅作参考。
voidCImage:
:
DrawImage(HDChdc,intiLeft,intiTop,intiWidth,intiHeight)
{
if(!
hdc||m_pImageData==NULL)
return;
BITMAPINFObmi;
memset(&bmi,0,sizeof(bmi));
bmi.bmiHeader.biSize=sizeof(BITMAPINFO);
bmi.bmiHeader.biWidth=m_iImageWidth;
bmi.bmiHeader.biHeight=m_iImageHeight;
bmi.bmiHeader.biPlanes=1;
bmi.bmiHeader.biBitCount=m_iBitsPerPixel;
bmi.bmiHeader.biCompression=BI_RGB;
bmi.bmiHeader.biSizeImage=m_iImageDataSize;
StretchDIBits(hdc,iLeft,iTop,iWidth,iHeight,
0,0,m_iImageWidth,m_iImageHeight,
m_pImageData,&bmi,DIB_RGB_COLORS,SRCCOPY);
}
6、3D(OpenGL)的不同之处
如果你是想用刚才我们得到的数据生成纹理对象,那么你还要请出下面的问题。
首先,用来生成纹理的数据不需要对齐,也就是说不能在每行的后面加上对齐的字节。
当然在OpenGL里要求纹理图片的尺寸为2的幂,所以这个问题实际上不存在;
其次,我们得到的图形数据格式是BGR(BGRA),所以在生成纹理的时候,需指定格式为GL_BGR_EXT(GL_BGRA_EXT);否则需要做BGR->RGB(BGRA->RGBA)的转化。
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
根据小赵的算法,对于16位次真对齐的方法如下:
((宽度+1)/2)*4=每一行实际的字节数,它是4的整数倍,即32位对齐。
理解分辨率
我们常说的屏幕分辨率为640×480,刷新频率为70Hz,意思是说每行要扫描640个象素,一共有480行,每秒重复扫描屏幕70次。
理解调色板
有一个长宽各为200个象素,颜色数为16色的彩色图,每一个象素都用R、G、B三个分量表示。
因为每个分量有256个级别,要用8位(bit),即一个字节(byte)来表示,所以每个象素需要用3个字节。
整个图象要用200×200×3,约120k字节,可不是一个小数目呀!
如果我们用下面的方法,就能省的多。
因为是一个16色图,也就是说这幅图中最多只有16种颜色,我们可以用一个表:
表中的每一行记录一种颜色的R、G、B值。
这样当我们表示一个象素的颜色时,只需要指出该颜色是在第几行,即该颜色在表中的索引值。
举个例子,如果表的第0行为255,0,0(红色),那么当某个象素为红色时,只需要标明0即可。
让我们再来计算一下:
16种状态可以用4位(bit)表示,所以一个象素要用半个字节。
整个图象要用200×200×0.5,约20k字节,再加上表占用的字节为3×16=48字节.整个占用的字节数约为前面的1/6,省很多吧?
这张R、G、B的表,就是我们常说的调色板(Palette),另一种叫法是颜色查找表LUT(LookUpTable),似乎更确切一些。
Windows位图中便用到了调色板技术。
其实不光是Windows位图,许多图象文件格式如pcx、tif、gif等都用到了。
所以很好地掌握调色板的概念是十分有用的。
有一种图,它的颜色数高达256×256×256种,也就是说包含我们上述提到的R、G、B颜色表示方法中所有的颜色,这种图叫做真彩色图(truecolor)。
真彩色图并不是说一幅图包含了所有的颜色,而是说它具有显示所有颜色的能力,即最多可以包含所有的颜色。
表示真彩色图时,每个象素直接用R、G、B三个分量字节表示,而不采用调色板技术。
原因很明显:
如果用调色板,表示一个象素也要用24位,这是因为每种颜色的索引要用24位(因为总共有224种颜色,即调色板有224行),和直接用R,G,B三个分量表示用的字节数一样,不但没有任何便宜,还要加上一个256×256×256×3个字节的大调色板。
所以真彩色图直接用R、G、B三个分量表示,它又叫做24位色图。
bmp文件格式
介绍完位图和调色板的概念,下面就让我们来看一看Windows的位图文件(.bmp文件)的格式是什么样子的。
bmp文件大体上分成四个部分,如图1.3所示。
位图文件头BITMAPFILEHEADER
位图信息头BITMAPINFOHEADER
调色板Palette
实际的位图数据ImageDate
图1.3Windows位图文件结构示意图
第一部分为位图文件头BITMAPFILEHEADER,是一个结构,其定义如下:
typedefstructtagBITMAPFILEHEADER{
WORDbfType;
DWORDbfSize;
WORDbfReserved1;
WORDbfReserved2;
DWORDbfOffBits;
}BITMAPFILEHEADER;
这个结构的长度是固定的,为14个字节(WORD为无符号16位整数,DWORD为无符号32位整数),各个域的说明如下:
bfType
指定文件类型,必须是0x424D,即字符串“BM”,也就是说所有.bmp文件的头两个字节都是“BM”。
bfSize
指定文件大小,包括这14个字节。
bfReserved1,bfReserved2
为保留字,不用考虑
bfOffBits
为从文件头到实际的位图数据的偏移字节数,即图1.3中前三个部分的长度之和。
第二部分为位图信息头BITMAPINFOHEADER,也是一个结构,其定义如下:
typedefstructtagBITMAPINFOHEADER{
DWORDbiSize;
LONGbiWidth;
LONGbiHeight;
WORDbiPlanes;
WORDbiBitCount
DWORDbiCompression;
DWORDbiSizeImage;
LONGbiXPelsPerMeter;
LONGbiYPelsPerMeter;
DWORDbiClrUsed;
DWORDbiClrImportant;
}BITMAPINFOHEADER;
这个结构的长度是固定的,为40个字节(LONG为32位整数),各个域的说明如下:
biSize
指定这个结构的长度,为40。
biWidth
指定图象的宽度,单位是象素。
biHeight
指定图象的高度,单位是象素。
biPlanes
必须是1,不用考虑。
biBitCount
指定表示颜色时要用到的位数,常用的值为1(黑白二色图),4(16色图),8(256色),24(真彩色图)(新的.bmp格式支持32位色,这里就不做讨论了)。
biCompression
指定位图是否压缩,有效的值为BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS(都是一些Windows定义好的常量)。
要说明的是,Windows位图可以采用RLE4,和RLE8的压缩格式,但用的不多。
我们今后所讨论的只有第一种不压缩的情况,即biCompression为BI_RGB的情况。
biSizeImage
指定实际的位图数据占用的字节数,其实也可以从以下的公式中计算出来:
biSizeImage=biWidth’×biHeight
要注意的是:
上述公式中的biWidth’必须是4的整倍数(所以不是biWidth,而是biWidth’,表示大于或等于biWidth的,最接近4的整倍数。
举个例子,如果biWidth=240,则biWidth’=240;如果biWidth=241,biWidth’=244)。
如果biCompression为BI_RGB,则该项可能为零
biXPelsPerMeter
指定目标设备的水平分辨率,单位是每米的象素个数,关于分辨率的概念,我们将在第4章详细介绍。
biYPelsPerMeter
指定目标设备的垂直分辨率,单位同上。
biClrUsed
指定本图象实际用到的颜色数,如果该值为零,则用到的颜色数为2biBitCount。
biClrImportant
指定本
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- BMP 图像格式 详解