最近公司里面有一个需要将yuv保存成bmp文件的任务,但是由于我对bmp文件存储格式不太了解,下面进行了一番搜索,实操,有了这篇文章。最近在学数字图像处理,正好里面也有,所以我感觉这篇文章应该能解决很多人对bmp文件存储格式的疑问。
BMP文件组成
bmp文件是由四部分组成的,其中第三部分位图颜色标可以是有的,也可以是没有的,在下面的内容中会解释到。
首先来看第一部分
位图文件头结构
首先先来看下位图文件头结构
typedef struct tagBITMAPFILEHEADER
{
WORD bfType;//BM
DWORD bfSize;//文件大小
WORD bfReserved1;//0
WORD bfReserved2;//0
DWORD bfOffBits;//位图数据的起始位置
}BITMAPFILEHEADER;
首先来看这个数据结构
- bfType两个字节,如果是BMP,那么它就会显示BM
- bfSize四个字节,代表文件大小
- bfReserved1和bfReserved2是保留字,默认设置为0,也是两个字节
- bfOffBits是位图数据的起始位置,是四个字节
所以文件头一共占用了14个字节
位图信息头结构
组成的第二部分是位图信息头,结构体如下
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;//每个像素所需的位数
DWORD biCompression;//位图压缩类型
DWORD biSizeImage;//位图的大小
LONG biXpelPerMeter;//
LONG biYPelPerMeter;//
DWORD biClrUsed;//颜色数
DWORD biClrImportant;//重要的颜色数
}BITMAPINFOHEADER
biSize:代表信息头大小
biWidth:图像宽
biHeight:图像高
biPanlanes:位元面数,一般为1
biBitCount:每个像素所需要的位数
biCompression:位图压缩类型,一般为0就是不压缩
biSizeImage:位图的大小
后面16个字节默认都设置为0
位图颜色表
首先先来看下位图颜色表的结构体
typedef struct tagRGBQUAD
{
BYTE rgbBlue;//蓝色
BYTE rgbGreen;//绿色
BYTE rgbRed;//红色
BYTE rgbReserved;//0
}RGBQUAD
位图颜色表可以存在也可以不存在,要根据图像是怎么样的,在后面的例子中会提到。
位图像素数据
struct tagBITMAPINFO
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];//颜色表
}
用实例来理解上面结构体部分
我这里有一个我保存下来的BMP文件
这里要用到一款工具 ultraedit。
用ue打开这张图,我们可以看一串十六进制,如下图
通过上面的文件头,信息头等结构体来分析这段。
文件头解析
首先是文件头,我们先把它的结构体摘抄下来。
typedef struct tagBITMAPFILEHEADER
{
WORD bfType;//BM
DWORD bfSize;//文件大小
WORD bfReserved1;//0
WORD bfReserved2;//0
DWORD bfOffBits;//位图数据的起始位置
}BITMAPFILEHEADER;
一共十四个字节,我们来看下这张1.bmp的bfType,bfType一共占2个字节,那么就是0和1,是42和4D,转换成十进制,对应的ASCII码是BM
bfSize占4个字节,所以应该是2 3 4 5位置,那么对应的是36 EC 5E 00,由于是小端存储,所以我们得到的应该是 00 5E EC 36,转换的十进制是6,220,854,得到是文件大小的字节,字节转换成KB或者MB,自己去除1024就行,就能得到这个1.bmp的大小了。
后面的bfReserved1和bfReserved2都是2个字节的保留字,那么一共四个字节 也就是 6 7 8 9。如下图。
头文件最后是bfOffBits,是数据区起始位置,占4个字节,就是 a b c d ,对应的是 36 00 00 00,如下图所示。
看到是36,那么我们可以看到 36h位置,也就是我下图中红色框部分。
到此文件头部分已经结束。
信息头解析
先把信息头部分对应的结构体摘抄下来
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;//每个像素所需的位数
DWORD biCompression;//位图压缩类型
DWORD biSizeImage;//位图的大小
LONG biXpelPerMeter;//
LONG biYPelPerMeter;//
DWORD biClrUsed;//颜色数
DWORD biClrImportant;//重要的颜色数
}BITMAPINFOHEADER
首先第一个是biSize,也就是信息头大小,从结构体可知,信息头加起来是40,所以我们应该找到biSize的大小是40,当然这是十进制的,转换成十六进制的是28。这只是我们一个推理过程,那么我实际从数据中来看,前面的文件头是14个字节了,现在到16字节,biSize是占4个字节,也就是下面图中红框部分。
这就是信息头biSize部分。
biWidth和biHeight都占4个字节,把对应部分抄下来
biWidth:80 07 00 00 小端 就是 00 00 07 80 十进制是1920
biHeight:38 04 00 00 小端 就是 00 00 04 38 十进制是1080
所以我们知道了这张bmp图是1920*1080。
biPlanes占2个字节,默认是1,对应下图红框部分
biBitCount占2个字节,代表每个像素所占的位数,下图中18是十六进制,转换为十进制就是24。
biCompression默认为0,占用4个字节。(如下图红框所示)
后面部分四个字节代表图像大小,最后26-35可以都设置为0
由于它是24位真彩色,所以是没有调色板的,那么从36这里,也就是4C开始都是它的位图数据区。
NOTE:关于有调色板的例子,到时候再编辑文章。