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位深则直接存储颜色数据。
字节[0] | 字节[1] | ||
pixel[1] | pixel[0] | 0000 | pixel[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>