这里是bmp图像格式内容分析,实战读取、写入bmp请走传送门:http://t.csdnimg.cn/rjrWE
目录
1、前言
BMP文件格式,又称为Bitmap(位图)或是DIB(Device-Independent Device,设备无关位图),是Windows系统中广泛使用的图像文件格式。由于它可以不作任何变换地保存图像像素域的数据,因此成为我们取得RAW数据的重要来源。Windows的图形用户界面(graphical user interfaces)也在它的内建图像子系统GDI中对BMP格式提供了支持。
BMP文件的数据按照从文件头开始的先后顺序分为四个部分:
- 位图文件头(bitmap file header):提供文件的格式、大小等信息
- 位图信息头(bitmap information):提供图像数据的尺寸、位平面数、压缩方式、颜色索引等信息
- 调色板(color palette):可选,如使用索引来表示图像,调色板就是索引与其对应的颜色的映射表
- 位图数据(bitmap data):就是图像数据
数据段名称 | 对应的Windows结构体定义 | 大小(Byte) |
---|---|---|
位图文件头 | BITMAPFILEHEADER | 14 |
位图信息头 | BITMAPINFOHEADER | 40 |
调色板 | 由颜色索引数决定 | |
位图数据 | 由图像尺寸决定 |
我们一般见到的图像以24位图像为主,即R、G、B三种颜色各用8个bit来表示,这样的图像我们称为真彩色,这种情况下是不需要调色板的,也就是所位图信息头后面紧跟的就是位图数据了。因此,我们常常见到有这样一种说法:位图文件从文件头开始偏移54个字节就是位图数据了,这其实说的是24或32位图的情况。这也就解释了我们按照这种程序写出来的程序为什么对某些位图文件没用了。
可见我的这幅bmp图是24位图,不需要调色板。
2、bmp结构
接下来就需要查看bmp的十六进制代码。如何查看详情参见另一篇博客https://blog.csdn.net/weixin_55696427/article/details/134163597?spm=1001.2014.3001.5502
位图文件头
Bitmap File Header | |||
---|---|---|---|
位置(hex/dec) | 尺寸(byte) | 描述 | |
00 | 0 | 2 | 头文件字段,说明文件类型 对于bmp文件,内容为0×424D,对应ASCll码BM |
02 | 2 | 4 | 整个.bmp文件大小(little endian) |
06 | 6 | 2 | 预留字段,通常为0 |
08 | 8 | 2 | |
0A | 10 | 4 | 图片信息的开始位置 |
我们直接看十六进制文件:
位置 00,尺寸 2,内容 42 4D,表示这是Windows支持的位图格式。
位置 02,尺寸 4,内容 16 f9 08 00,表示文件大小。因为是 little endian(靠前的数字对应低数位),所以实际十六进制数字为 00 08 f9 16。对应十进制数字为:
8×16^4+15×16^3+9×16^2+1×16^1+6×16^0=588054,下图展示了本图片的大小,可以发现是一样的。
位置 06,尺寸 2,内容 00 00,预留字段,通常为 0。
位置 08,尺寸 2,内容 00 00,同上。
位置 0A,尺寸 4,内容 36 00 00 00,表示位图数据的开始位置。同样为 little endian,对应十进制数字为 54(这也是文件头的总长度)。
位图信息头
Bitmap Information Header | |||
---|---|---|---|
位置(hex/dec) | 尺寸(byte) | 描述 | |
0E | 14 | 4 | 信息头大小,一般为40byte |
12 | 18 | 4 | 图像宽度(little endian) |
16 | 22 | 4 | 图像高度(little endian) |
1A | 26 | 2 | 色彩平面的数量,必须为1 |
1C | 28 | 2 | 每像素用多少bit来表示 |
1E | 30 | 4 | 采用何种压缩方式 通常不压缩,即BI_RGB,对应值为0 |
22 | 34 | 4 | 图片大小(原始位图数据的大小) 对于不压缩的图片,可以设置为0 |
26 | 38 | 4 | 横向分辨率(像素/米) |
2A | 42 | 4 | 纵向分辨率(像素/米) |
2E | 46 | 4 | 调色板中颜色数量 通常为0 |
32 | 50 | 4 | 重要颜色数量(通常被忽略) 通常为0,表示每种颜色都重要 |
位置 0E,尺寸 4,内容 28 00 00 00,意思是 DIB header 大小。对应十进制数字为 40 (little endian)。
位置 12,尺寸 4,内容 18 01 00 00,代表图像宽度。实际十六进制数字为00 00 01 18,对应十进制280 。
位置 16,尺寸 4,内容 bc 02 00 00,代表图像高度。实际十六进制数字为00 00 02 bc,对应十进制700 。
位置 1A,尺寸 2,内容 01 00,表示色彩平面的数量,必须为 1。
位置 1C,尺寸 2,内容 18 00,表示每像素用多少比特来表示。对应十进制 24。
位置 1E,尺寸 4,内容 00 00 00 00,表示采用何种压缩方式。此处为不压缩。
位置 22,尺寸 4,内容 e0 f8 08 00,表示原始位图数据的大小。实际十六进制数字为00 08 f8 e0,对应十进制588000 。
剩下的都是0,横、纵分辨率缺省。
原始位图数据
下图为原始位图数据开头部分
补零问题
Windows默认的扫描的最小单位是4字节,如果数据对齐满足这个值的话对于数据的获取速度等都是有很大的增益的。因此,BMP图像顺应了这个要求,要求每行的数据的长度必须是4的倍数,如果不够需要进行比特填充(以0填充),这样可以达到按行的快速存取。这时,位图数据区的大小就未必是 图片宽×图片高×每像素字节数 能表示的了,因为每行可能还需要进行比特填充。
填充后的每行的字节数为:
所以本图像每行字节数为 (计算时向下取整)
数据大小就是840*700=588000,与之前都是一致的。
本次我使用的图像每像素 24 比特(3 字节),大小280x700,那么数据大小应该为280x700x3=588000,这也与计算一致,说明本次图像没有额外的补零。
像素数据
由于位图信息头中的图像高度是正数,所以位图数据在文件中的排列顺序是从左下角到右上角,以行为主序排列的。即我们见到的第一个像素是图像最左下角的,本图为00 00 00,表示纯黑。
从数据中看,每三个字节表示一个像素,按照BGR的顺序。三个三个一组,一组为一个像素。可以发现前41个像素都是纯黑的。第42个像素开始有颜色了为16 16 2e。
那么实际真是这样吗?下面是我这张图的左下角部分,利用画图工具打开。
坐标为40,但实际是第41个像素(因为从0开始),汲取该点像素后发现其三色果然全为0。
坐标为41,但实际是第42个像素,汲取该点像素后发现其RGB色为46 22 22,十六进制下为2E 16 16,与位图数据中一样。
总结
本次并没有调色板,所以暂时不予考虑,日后待续。
参考: