BMP (Bitmap)文件格式也就是位图
下面我用一张 1位的图片来研究BMP文件的数据格式,找到对应信息,初学,如有错误请指出谢谢。
1、文件信息(14字节)
typedef struct tag_bitmap_file_header{
unsigned short file_type;//文件类型,BMP 文件值固定为 0x4D42,存储为小端模式,转换成 ASCII 就是 “BM”
unsigned int file_size;//整个文件的大小,以字节为单位
unsigned short reserved1;//保留
unsigned short reserved2;//保留
unsigned int offset_bits;//位图数据在文件中的偏移值,等于 “文件信息+位图信息+调色板信息”
} __attribute__((packed)) bitmap_file_header;
这个结构体的大小固定为 14 个字节
一个字节等于二进制位的8位。short 占 2个字节,int 占4个字节,char 1个。在我的图片数据上找位置如下:
文件大小 0x50=80字节和图片符合, 数据位置在0x3E=62
2、位图信息 (40字节)
typedef struct tag_bitmap_info_header {
unsigned int bitmap_info_size;//位图信息的大小,固定为 40
int bitmap_width;//位图宽度
int bitmap_height;//位图高度,影响位图数据的存储方式。值为正数时,从位图数据的最后一行开始保存,也就是文件位图数据的第一行是图片数据的最后一行,这种存储方式支持压缩。值为负数时,文件位图数据的第一行就是图片数据的第一行
unsigned short planes;//位图的位面数,固定为 1
unsigned short image_depth;//位图的图像深度,(1,4,8,16,24,32)表示位图数据中,几个二进制位表示一个像素点,如 8 bits 表示,8 个二进制位表示一个像素点
unsigned int compression;//位图压缩类型,必须是 0(BI_RGB 不压缩 ), 1(BI_RLE8 压缩类型 ),2(BI_RLE4压缩类型)
unsigned int image_size;//位图的数据大小
int x_pels_permeter;//指定位图目标设备的水平打印分辨率,表示水平方向每米的像素点数量,可以是 0
int y_pels_permeter;//指定位图目标设备的垂直打印分辨率,表示垂直方向每米的像素点数量,可以是 0
unsigned int color_used;//位图实际使用的颜色表中的颜色所有数,为0使用所有调色板项
unsigned int color_important;
} __attribute__((packed)) bitmap_info_header;//重要的颜色数量,值通常等于 color_used,值为 0 时表示所有颜色都重要
这个结构体的大小固定为 40 个字节
大小 0x28 = 40 宽度 0x21=33 高度 0x02=2 位深 0x01=1 符合(两行结束和开头的黄色框是一起的)
3、调色板信息 (xx字节)
typedef struct tag_bitmap_palette {
unsigned char blue;//该颜色的蓝色分量
unsigned char green;//该颜色的绿色分量
unsigned char red;//该颜色的红色分量
unsigned char reserved;//保留字节
} __attribute__((packed)) bitmap_palette;
这个结构体的大小固定为 4 个字节。
可选,调色板就是索引与其对应的颜色的映射表。当小于等于8bit 时,必带有调色板信息,数据存的是颜色值对应调色板颜色的索引值。bmp 1位 数据存的是调色板的索引值,超过8位存的是数据。
这张图片存2个颜色,索引0 位置 为 #ffffff ,索引1 为#000000
4、位图数据 (xx字节)
BMP文件存储位图数据时,图像的扫描方式是在行内按从左到右扫描、在行间从下到上扫描的顺序。Windows规定图像文件中,一个图像的扫描行所占的字节数必须是4的倍数(即以字为单位),不足的以0填充
色深1位,8个像素占1个字节; (11111111)
色深4位,2个像素占1个字节; (1111)(0000)
色深8位,1个像素占1个字节;
色深24位,1个像素占3个字节;
对于BMP等位图来说,要求是4字节对齐,即每行字节数必须为4的整数倍,因此满足以4字节为对齐单位向下对齐,所以每行字节数为:(8Bit = 1Byte)
ulong rows_len = (((biWidth * biBitCount) / 8 + 3) / 4) * 4
当BMP图位宽不足 8 时,多个像素才占用 1Byte,因此可以将除8外移,同时因为字节数必须为4的整数倍,3 * 8需变成31,则行字节数为:
ulong rows_len = (((biWidth * biBitCount) + 31) / 32) * 4 或
ulong rows_len = ((biWidth*biBitCount + 31) >>5)<<2;
所以 扫描行实际长度(包含填充)rows_len = 8,开始找数据位置:
62开始,图片是从下往上扫描,所以红色框是图片第二行的数据,黄色框是第一行的数据,最后补齐两字节。(色深为1-8 数据存的是调色板的索引,超过存的是实际颜色数据,注意调色板存的顺序是 bgr 例如取数据bgr时顺序别用反)
色深位1 ,宽高:33*2 == 66像素 ,1像素点占1个二进制位位,以一行为例:
00 00 ff ff 80 00 00 00
00000000 00000000 11111111 11111111 10000000 00000000 0000000 00000000
00000000 00000000 11111111 11111111 1 这33位是数据,对应的调色板索引,所以图片是从白到黑色,如下图:
参考:https://blog.youkuaiyun.com/u012313335/article/details/80432155
https://blog.youkuaiyun.com/lk_luck/article/details/115122351