【文件格式】BMP文件格式

1.BMP文件组成

BMP文件从头开始,按顺序由下面4部分组成:(图片均引用于http://www.cnblogs.com/xiehy/archive/2011/06/07/2074405.html)

  • 文件头:包含图像文件类型,文件总大小和位图数据区相对文件起始位置的偏移量
    • 文件类型对于BMP文件而言是固定为0x4D42;
    • 文件大小则为”文件头+位图信息头+调色板数据+位图数据区大小“;
    • 位图数据区偏移量表示为”文件头+位图信息头+调色板数据“的大小。
typedef struct{
	unsigned short int filetype;//0x4D42
	int filesize;
	short int reserved1;//0x0000
	short int reserved2;//0x0000
	int fileoffbits; 
}bmpfileheader;

  • 位图信息头:包含图像文件像素尺寸,图片显示层数,位图深度,压缩类型(待续测试),位图数据区大小,XY轴实际尺寸和像素之间的关系(像素/米,跟打印相关),实际使用的调色板中的颜色索引数(待续测试),图像显示有重要影响的颜色索引数(待续测试)

typedef struct{
	int infosize; //40
	unsigned int width;
	unsigned int height;
	unsigned short int plane; //0x01
	unsigned short int bmpbit; //1,2,4,8,16,24
	unsigned int bitcompress; //0,1,2
	unsigned int bmpdatasize; 
	unsigned int biXPelsPerMeter;  
	unsigned int biYPelsPerMeter;  
	unsigned int colorused; 
	unsigned int colorimportant; 
}bmpinfoheader;

  • 调色板:当位图深度不足24位的时候,如果每个像素均使用24位(即RGB各3个字节)来表示,将降低存储效率,所以就有调色板的存在。调色板其实是颜色的索引表,当存在调色板时,位图数据区存储的就不是RGB值而是颜色索引号。读取图像的程序会根据位图信息中的位图深度和使用索引数决定如何解析位图数据区的内容。
typedef struct{
	unsigned char blue;
	unsigned char green;
	unsigned char red;
	unsigned char reserved; //this may be Alpha(表示透明通道,BMP不用) 0x00
}rgbquad;
  • 位图数据区:如果存在调色板则存储索引号,如果超过24位深则直接存储颜色数据。
值得注意的是,当存储索引号,如果索引数不为256的整数倍,那么索引号使用N个字节存储同样会浪费空间,所以做法就是索引数量需要用几个bit表示,我们就用几个bit进行存储;BMP位图数据区存储是以行为单位的,每行存储位图信息中宽度个像素的索引号,当该行最后一个像素索引号不能填满最后一个字节的时候,空白处补0即可。如位深为4的图片,每个像素可选调色板的16种颜色之一,当图片宽度为3时,单行数据存储方式如下:
字节[0]字节[1]
pixel[1]pixel[0]0000pixel[2]
值得注意的是,位图存储数据是以最后一行开始扫描,所以图片存储是上下颠倒的形式记录的。

下面附上测试用代码:(如有需要可以修改上面的bmp生成函数,后面也会用到这个来进行二维码生成和图像分形的学习用)
#include <stdio.h>
#include <stdio h="">
#include <stdlib h="">
#include <string h="">
#include <math h="">

typedef struct{
	unsigned short int filetype;//0x4D42
	int filesize; 
	short int reserved1;//0x0000
	short int reserved2;//0x0000
	int fileoffbits; //fileoffbits=sizeof(bmpfileheader)(14B)+sizeof(bmpinfoheader)(40B)+µ÷É«°å´óС
}bmpfileheader;

typedef struct{
	int infosize; //40
	unsigned int width;
	unsigned int height;
	unsigned short int plane; //0x01
	unsigned short int bmpbit; //1,2,4,8,16,24
	unsigned int bitcompress; 
	unsigned int bmpdatasize; 
	unsigned int biXPelsPerMeter;  
	unsigned int biYPelsPerMeter;  
	unsigned int colorused;  
	unsigned int colorimportant; 
}bmpinfoheader;

typedef struct{
	unsigned char blue;
	unsigned char green;
	unsigned char red;
	unsigned char reserved; //this may be Alpha(表示透明通道) 0x00
}rgbquad;

void gen_monobmp(char *data, unsigned int width, unsigned int height, FILE *fp){
	bmpfileheader myheader;
	bmpinfoheader myinfo;
	rgbquad mypalette[2];
	char *ptr;
	unsigned int x, y;
	unsigned int *linebyte, temp;
	unsigned int linebytenum, bytepixels;
	unsigned char mask;
	unsigned int byteoffset;

	myinfo.infosize = 40;
	myinfo.width = width;
	myinfo.height = height;
	myinfo.bitcompress = 0;
	myinfo.bmpbit = 1;

	linebytenum = (width*myinfo.bmpbit+31)>>5;
	linebyte = (unsigned int*)calloc(linebytenum, sizeof(unsigned int));
	bytepixels = 32/myinfo.bmpbit;
	mask = 0xFF>>(8-myinfo.bmpbit);

	myinfo.bmpdatasize = height*linebytenum*sizeof(int); //width*height*sizeof(char);
	myinfo.biXPelsPerMeter = 0;
	myinfo.biYPelsPerMeter = 0;
	myinfo.colorimportant = 0;
	myinfo.colorused = 0;
	myinfo.plane = 1;

	myheader.filetype = 0x4D42;
	myheader.filesize = 14+40+2*sizeof(rgbquad)+height*linebytenum*sizeof(int);
	myheader.reserved1 = 0x0000;
	myheader.reserved2 = 0x0000;
	myheader.fileoffbits = 14+40+2*sizeof(rgbquad);

	mypalette[0].blue = 255; mypalette[0].green = 255; mypalette[0].red = 255; mypalette[0].reserved = 0;  //white
	mypalette[1].blue = 0;   mypalette[1].green = 0;   mypalette[1].red = 255; mypalette[1].reserved = 0;  //red

	ptr = (char*)&myheader;
	fwrite(ptr, 1, 2, fp);
	ptr = (char*)&myheader.filesize;
	fwrite(ptr, 1, 12, fp);

	ptr = (char*)&myinfo;
	fwrite(ptr, 1, 40, fp);

	ptr = (char*)&mypalette;
	fwrite(ptr, 1, sizeof(rgbquad)*2, fp);

	for(x=height; x>0; x--){
		memset(linebyte, 0, sizeof(int)*linebytenum);
		for(y=0; y<width; ++y){
			byteoffset = myinfo.bmpbit*(y%bytepixels);
			temp = (*(data+(x-1)*height+y)&mask)<<(((byteoffset>>3)<<3+(8-myinfo.bmpbit-byteoffse%8); 
                        linebyte[y/bytepixels]=linebyte[y/bytepixels]=|temp; 
                ptr = (char*)linebyte;
		fwrite(ptr, 1, linebytenum*sizeof(int), fp);
	}
}

const char path[] = "first.bmp";
int main(int argc, char *argv[]){
	char *data;
	int width, height;
	int x, y, fileid;
	FILE *fp;
	char filename[20];

	/**********************************************************************************************/
	//gen data  
	width = 200; height = 200;
	data = (char*)malloc(sizeof(char)*width*height);
	fileid = 0;
	while(fileid>=0){
		switch(fileid){
			case 0:
				sprintf(filename, "./%02d.bmp", fileid);
				for(x=0; x<height; ++x){
					for(y=0; y<width y="" if="" x="">=height/2&&y<=width/2)
							*(data+x*height+y)=1;
						else if(x<=height/2&&y>=width/2)
							*(data+x*height+y)=1;
						else
							*(data+x*height+y)=0;
					}
				}
				fp = fopen(filename, "wb");
				gen_monobmp(data, width, height, fp);
				fclose(fp);
				fileid++;
				break;
			case 1:
				sprintf(filename, "./%02d.bmp", fileid);
				for(x=0; x<height; ++x){
					for(y=0; y<width y="" if="" x="">=y)
							*(data+x*height+y)=1;
						else
							*(data+x*height+y)=0;
					}
				}
				fp = fopen(filename, "wb");
				gen_monobmp(data, width, height, fp);
				fclose(fp);
				fileid++;
				break;
			case 2:
				sprintf(filename, "./%02d.bmp", fileid);
				for(x=0; x<height; ++x){
					for(y=0; y<width; ++y){
						*(data+x*height+y)=1;
					}
				}
				fp = fopen(filename, "wb");
				gen_monobmp(data, width, height, fp);
				fclose(fp);
				fileid++;
				break;
			case 3:
				sprintf(filename, "./%02d.bmp", fileid);
				for(x=0; x<height; ++x){
					for(y=0; y<width; ++y){
						if(x%2==y%2)
							*(data+x*height+y)=1;
						else 
							*(data+x*height+y)=0;
					}
				}
				fp = fopen(filename, "wb");
				gen_monobmp(data, width, height, fp);
				fclose(fp);
				fileid++;
				break;
			case 4:
				sprintf(filename, "./%02d.bmp", fileid);
				for(x=0; x<height; ++x){
					for(y=0; y<width; ++y){
						if(x==y)
							*(data+x*height+y)=1;
						else
							*(data+x*height+y)=0;
					}
				}
				fp = fopen(filename, "wb");
				gen_monobmp(data, width, height, fp);
				fclose(fp);
				fileid++;
				break;
			case 5:
				sprintf(filename, "./%02d.bmp", fileid);
				for(x=0; x<height; ++x){
					for(y=0; y<width; ++y){
						if(pow((double)x-height/2,2)+pow((double)y-width/2,2) < pow((double)height/2,2)-1)
							*(data+x*height+y)=1;
						else
							*(data+x*height+y)=0;
					}
				}
				fp = fopen(filename, "wb");
				gen_monobmp(data, width, height, fp);
				fclose(fp);
				fileid++;
				break;	
			default:
				fileid = -1;
				break;
		}
	}
	/******************************************************/

	getchar();
	getchar();
	return 0;
}
</width></width><!--3--><!--3--></math></string></stdlib></stdio>






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值