BMP(全称Bitmap)是Windows操作系统中的标准图像文件格式,可以分成两类:设备相关位图(DDB)和设备无关位图(DIB),使用非常广。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大。BMP文件的图像深度可选lbit、4bit、8bit及24bit。BMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。由于BMP文件格式是Windows环境中交换与图有关的数据的一种标准,因此在Windows环境中运行的图形图像软件都支持BMP图像格式。
先解释下数据存贮方式:
最常见的就是24位图,所谓的24位图,就是说一个像素的颜色信息用24位来表示,也就是说,对于三原色BRG,每一个颜色都用以字节(8)位来表示。除了24位图,还有1位(单色),2位(4色,CGA),4位(16色,VGA),8位(256色),16位(增强色),24位(真彩色)和32位等
bmp文件头包含如下信息:
- bfType:2字节,文件类型;
- bfSize:4字节,文件大小;
- bfReserved1:2字节,保留,必须设置为0;
- bfReserved2:2字节,保留,必须设置为0;
- bfOffBits:4字节,从头到位图数据的偏移;
- biSize:4字节,信息头的大小,即40;
- biWidth:4字节,以像素为单位说明图像的宽度;
- biHeight:4字节,以像素为单位说明图像的高度,同时如果为正,说明位图倒立(即数据表示从图像的左下角到右上角),如果为负说明正向;
- biPlanes:2字节,为目标设备说明颜色平面数,总被设置为1;
- biBitCount:2字节,说明比特数/像素数,值有1、2、4、8、16、24、32;
- biCompression:4字节,说明图像的压缩类型,最常用的就是0(BI_RGB),表示不压缩;
- biSizeImages:4字节,说明位图数据的大小,当用BI_RGB格式时,可以设置为0;
- biXPelsPerMeter:表示水平分辨率,单位是像素/米,有符号整数;
- biYPelsPerMeter:表示垂直分辨率,单位是像素/米,有符号整数;
- biClrUsed:说明位图使用的调色板中的颜色索引数,为0说明使用所有;
- biClrImportant:说明对图像显示有重要影响的颜色索引数,为0说明都重要;
索引 | 蓝 | 绿 | 红 | Alpha |
0 | 01 | 10 | 37 | 00 |
1 | 00 | 10 | 49 | 00 |
2 | 00 | 18 | 44 | 00 |
3 | 01 | 1D | 58 | 00 |
- biBitCount=0x0018=24;
- bfWidth=0x000001c6=454;
- bfHeight=0x00000053=83;
- biSizeImage=0x0001BA3c=113212;
代码展示:
C语言结构体定义:
struct bmp_file //BMP文件头结构
{
char type[2]; //位图文件的类型,必须为BM,我这里类型不对,所以显示有误。
unsigned int size; //位图文件的大小,以字节为单位
short rd1; // 位图文件保留字,必须为0
short rd2; // 位图文件保留字,必须为0
unsigned int offset; // 位图数据的起始位置,以相对于位图
};
struct bmp_info //图像信息区
{
unsigned int bsize; //本结构体所占用字节数,即40个字节
int width; // 位图的宽度,以像素为单位,像素数量是4字节对齐的
int height; // 位图的高度,以像素为单位
unsigned short planes; // 目标设备的级别,必须为1
unsigned short count; // 每个像素所需的位数,必须是1(双色)// 4(16色),8(256色)或24(真彩色)之一
unsigned int compression; // 位图压缩类型,必须是 0(不压缩),// 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
unsigned int sizeimage; // 位图的大小,以字节为单位
unsigned int xmeter; // 位图水平分辨率,每米像素数
unsigned int ymeter; // 位图垂直分辨率,每米像素数
unsigned int cused; // 位图实际使用的颜色表中的颜色数
unsigned int cimportant; // 位图显示过程中重要的颜色数
};
struct bmp_head {
struct bmp_file file;
struct bmp_info info;
};
struct bmp_attr {
struct bmp_head head;
int xsize, ysize,sizeimage;
int pixel_size;
int line_length;
unsigned int offset;
};
struct bmp_attr *bmp = (struct bmp_attr *)calloc(1, sizeof(struct bmp_attr));
//读取bmp的文件头
fread(bmp, sizeof(struct bmp_attr), 1, fp);
bmp->xsize = (bmp->head.info.width * 3 + 3) / 4 * 4; // 4字节补齐
bmp->ysize = bmp->head.info.height;
bmp->sizeimage = bmp->head.info.sizeimage;
bmp->offset = bmp->head.file.offset;
printf("bmp xsize = %d ysize = %d sizeimage = %d offset = %d\n",bmp->xsize,bmp->ysize,bmp->sizeimage,bmp->offset);
可以获取头文件的信息,打印出来验证。
下面关于图片数据信息的获取
for (ix = 0; ix < bmp->ysize; ++ix) {
//因为bmp文件的原点是左下角,所以bmp图片需要顺着y轴的反方向来读取
fseek(fp, bmp->head.file.offset + (bmp->ysize -1 - ix) * bmp->line_length+1, SEEK_SET); //最后一行开始读取
//读取一行像素数
fread(buf, 1, bmp->line_length, fp);
这样数据就可以读取完啦!
头都开好了,还不去试一下?