BMP文件格式

介绍:

在生活中我们经常会用到各种格式的图片文件,当中bmp文件算是最为基础的,其全称为bitmap image file(位图文件),别名device independent bitmap file(设备无关位图文件),后缀为.bmp,.dib。设备无关的意思为bmp文件的显示不依赖于操作系统、平台。bmp的文件格式使得它能够存储任意宽高、任意分辨率的二维数字化图片,不管是黑白的,有多种颜色的,还是色深不同的,亦或是选择了数据压缩、alpha通道,color profiles(颜色配置文件),都能实现需求。


BMP文件结构:

这里忽略以前使用的.dib格式,只关注.bmp。

   以win32 GDI为例:可分为FileHeader, InfoHeader, PixelArray(代指图像数据),ColorTable四部分。

1.

typedef struct tagBITMAPFILEHEADER {
	WORD    bfType;
	DWORD   bfSize;
	WORD    bfReserved1;
	WORD    bfReserved2;
	DWORD   bfOffBits;
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;

FileHeader: 
	bfType--声明文件类型为bmp, 具体数值为字符“BM”, ASCII码为0x4D42(十进制为19778)
	bfSize--文件大小(单位:字节),非文件实际占用空间大小
	bfReserved1、bfReserved2--保留区,默认为0
	bfOffBits--文件头开始到图像数据之间的偏移字节量

2.

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, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;

InfoHeader:
	biSize--相当于sizeof(BITMAPINFOHEADER)
	biWidth、biHeight--图像宽高(单位:像素)
	biPlanes--位面数,总是为1
	biBitCount--即像素位深(bpp, bits per pixel),常用24位(R8G8B8)与32位(R8G8B8,最高位保留)
	biCompression--压缩类型,常为BI_RGB(数值为0L)
	biSizeImage--图像大小(单位:字节),当压缩类型为BI_RGB时,取0
	biXPelsPerMeter--水平分辨率(单位:像素/米)
	biYPelsPerMeter--垂直分辨率(单位:像素/米)
	biClrUsed--实际所用ColorTable的颜色索引数(0代表使用全部)
	biClrImportant--对图像显示有重要影响的颜色索引数(0代表都重要)

3.

typedef struct tagRGBQUAD {
        BYTE    rgbBlue;
        BYTE    rgbGreen;
        BYTE    rgbRed;
        BYTE    rgbReserved;
} RGBQUAD;

RGBQUAD即组成调色板的元素,占4字节(红绿蓝各占1字节,剩下的保留)
调色板就相当于一个RGBQUAD数组,大小为2^biBitCount,举
个例子,黑白照片biBitCount为2,调色板RGBQUAD[2]只含黑(RGBQUAD(0,0,0))、
白(RGBQUAD(255,255,255))两种颜色,biClrUsed为2,颜色索引从0-1。
不过要注意,如biBitCount为16、24、32的位图在biCompression为BI_RGB时没有调色板。
这就使得BITMAPFILEHEADER的bfOffBits属性有用起来了,其可以让我们在不知道
bmp文件具体内存信息时直接找到像素数据(PixelArray)进行数据处理。

4.注意点

BMP文件记录高1像素的一整行像素时采取的单位是字节,根据biBitCount的不同每个像素点可得到的颜色范围是变化的(颜色索引数是变化的),所以我们规定每行像素的字节数与4字节对齐。
比如这一行有242个像素且bpp为1,那么计算得到每行字节数为242*1,由于补齐规则最后结果是244字节。
最后PixelArray = 244*biHeight;

如果你和我一样在了解了BMP文件格式后,去尝试相加BITMAPFILEHEADER、
BITMAPINFOHEADER、调色板、PixelArray计算过BMP文件大小,那么一般来说你得到的结果
与右键文件属性里得到的大小不一样。
这里我举一张8位的BMP(biBitCount == 8)图片为例,

BMP文件格式_第1张图片BMP文件格式_第2张图片

用代码取得这些头信息:

BMP文件格式_第3张图片BMP文件格式_第4张图片

BMP文件格式_第5张图片

其宽242px,高212px,bpp=8

sizeof(BITMAPFILEHEADER) = 14;
sizeof(BITMAPINFOHEADER) = 40;
每行字节数为242*1,补齐得到244字节/行,乘以高212,
sizeof(PixelArray) = 51728;
调色板RGBQUAD[2^8],但实际上我用的这张图片只用到了32种颜色(BiClrUsed = 32)
sizeof(ColorTable) = 32*sizeof(RGBQUAD); // 128

40+14+128+51728 = 51910 文件大小正确。


或者将图片后缀改为.dat, 用文本编辑器打开查看字节码,开头0x424d表明bmp文件:

BMP文件格式_第6张图片

观察字节码可以发现PixelArray部分的单字节数值都在0-31(0x1f)之间,刚好证明8位的bmp是由调色板中的索引值来得到每位像素点颜色的。

如果要读出8位bmp文件每个像素的RGB值,那么需要根据读出的索引值去映射ColorTable来得到。

为了验证这些推论,我将PixelArray的所有字节数事先读取出来,通过ColorTable将PixelArray的每个字节映射得到对应的RGB值, 再当作输入数据输入到一个可指定逐一像素颜色来生成24位位图的程序中生成图片,比对两幅图片即可。


5.实验相关代码:

链接:http://pan.baidu.com/s/1pLpjUjT

// 之前传到csdn上被删了= =,由于是个小实验。。没什么后续,就不传github了,网盘见吧2333

示意图:

BMP文件格式_第7张图片














你可能感兴趣的:(Normal)