BMP(全称Bitmap)是Windows操作系统中的标准图像文件格式。
典型的BMP图像文件由四部分组成:
1:BMP文件头(14字节)
BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。
typedef struct tagBITMAPFILEHEADER
{
WORD bfType;//位图文件的类型,必须为BM(1-2字节)
DWORD bfSize;//位图文件的大小,以字节为单位(3-6字节,低位在前)
WORD bfReserved1;//位图文件保留字,必须为0(7-8字节)
WORD bfReserved2;//位图文件保留字,必须为0(9-10字节)
DWORD bfOffBits;//位图数据的起始位置,以相对于位图(11-14字节,低位在前)
//文件头的偏移量表示,以字节为单位
}__attribute__((packed)) BITMAPFILEHEADER;
2:位图信息头(40字节)
BMP位图信息头数据用于说明位图的尺寸等信息。
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize;//本结构所占用字节数(15-18字节)
LONG biWidth;//位图的宽度,以像素为单位(19-22字节)
LONG biHeight;//位图的高度,以像素为单位(23-26字节)
WORD biPlanes;//目标设备的级别,必须为1(27-28字节)
WORD biBitCount;//每个像素所需的位数,必须是1(双色),(29-30字节)
//4(16色),8(256色)16(高彩色)或24(真彩色)之一
DWORD biCompression;//位图压缩类型,必须是0(不压缩),(31-34字节)
//1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
DWORD biSizeImage;//位图的大小(其中包含了为了补齐行数是4的倍数而添加的空字节),以字节为单位(35-38字节)
LONG biXPelsPerMeter;//位图水平分辨率,每米像素数(39-42字节)
LONG biYPelsPerMeter;//位图垂直分辨率,每米像素数(43-46字节)
DWORD biClrUsed;//位图实际使用的颜色表中的颜色数(47-50字节)
DWORD biClrImportant;//位图显示过程中重要的颜色数(51-54字节)
}__attribute__((packed)) BITMAPINFOHEADER;
3:颜色表
颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下:
typedef struct tagRGBQUAD
{
BYTE rgbBlue;//蓝色的亮度(值范围为0-255)
BYTE rgbGreen;//绿色的亮度(值范围为0-255)
BYTE rgbRed;//红色的亮度(值范围为0-255)
BYTE rgbReserved;//保留,必须为0
}__attribute__((packed)) RGBQUAD;
颜色表中RGBQUAD结构数据的个数有biBitCount来确定:
当biBitCount=1,4,8时,分别有2,16,256个表项;
当biBitCount=24时,没有颜色表项。
4:位图数据
位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:
当biBitCount=1时,8个像素占1个字节;
当biBitCount=4时,2个像素占1个字节;
当biBitCount=8时,1个像素占1个字节;
当biBitCount=24时,1个像素占3个字节,按顺序分别为B,G,R;
Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充。
#include
#include
#include
/*
位图头结构
*/
#pragma pack(1)
typedef struct tagBITMAPFILEHEADER
{
unsigned char bfType[2];//文件格式
unsigned long bfSize;//文件大小
unsigned short bfReserved1;//保留
unsigned short bfReserved2;
unsigned long bfOffBits; //DIB数据在文件中的偏移量
}fileHeader;
#pragma pack()
/*
位图数据信息结构
*/
#pragma pack(1)
typedef struct tagBITMAPINFOHEADER
{
unsigned long biSize;//该结构的大小
long biWidth;//文件宽度
long biHeight;//文件高度
unsigned short biPlanes;//平面数
unsigned short biBitCount;//颜色位数
unsigned long biCompression;//压缩类型
unsigned long biSizeImage;//DIB数据区大小
long biXPixPerMeter;
long biYPixPerMeter;
unsigned long biClrUsed;//多少颜色索引表
unsigned long biClrImporant;//多少重要颜色
}fileInfo;
#pragma pack()
/*
调色板结构
*/
#pragma pack(1)
typedef struct tagRGBQUAD
{
unsigned char rgbBlue; //蓝色分量亮度
unsigned char rgbGreen;//绿色分量亮度
unsigned char rgbRed;//红色分量亮度
unsigned char rgbReserved;
}rgbq;
#pragma pack()
int main()
{
/*存储RGB图像的一行像素点*/
unsigned char ImgData[3000][3];
/*将灰度图的像素存到一个一维数组中*/
unsigned char ImgData2[3000];
int i,j,k;
FILE * fpBMP,* fpGray;
fileHeader * fh;
fileInfo * fi;
rgbq * fq;
char filename1[20],filename2[20];
printf("输入图像文件名:");
scanf("%s",filename1);
if((fpBMP=fopen(filename1,"rb"))==NULL)
{
printf("打开文件失败");
exit(0);
}
printf("输出图像文件名:");
scanf("%s",filename2);
if((fpGray=fopen(filename2,"wb"))==NULL)
{
printf("创建文件失败");
exit(0);
}
fh=(fileHeader *)malloc(sizeof(fileHeader));
fi=(fileInfo *)malloc(sizeof(fileInfo));
//读取位图头结构和信息头
fread(fh,sizeof(fileHeader),1,fpBMP);
fread(fi,sizeof(fileInfo),1,fpBMP);
//修改头信息
fi->biBitCount=8;
fi->biSizeImage=( (fi->biWidth*3+3)/4 ) * 4*fi->biHeight;
//fi->biClrUsed=256;
fh->bfOffBits = sizeof(fileHeader)+sizeof(fileInfo)+256*sizeof(rgbq);
fh->bfSize = fh->bfOffBits + fi->biSizeImage;
//创建调色版
fq=(rgbq *)malloc(256*sizeof(rgbq));
for(i=0;i<256;i++)
{
fq[i].rgbBlue=fq[i].rgbGreen=fq[i].rgbRed=i;
//fq[i].rgbReserved=0;
}
//将头信息写入
fwrite(fh,sizeof(fileHeader),1,fpGray);
fwrite(fi,sizeof(fileInfo),1,fpGray);
fwrite(fq,sizeof(rgbq),256,fpGray);
//读取RGB图像素并转换为灰度值
for ( i=0;ibiHeight;i++ )
{
for(j=0;j<(fi->biWidth+3)/4*4;j++)
{
for(k=0;k<3;k++)
fread(&ImgData[j][k],1,1,fpBMP);
}
for(j=0;j<(fi->biWidth+3)/4*4;j++)
{
ImgData2[j]=int( (float)ImgData[j][0] * 0.114 +
(float)ImgData[j][1] * 0.587 +
(float)ImgData[j][2] * 0.299 );
}
//将灰度图信息写入
fwrite(ImgData2,j,1,fpGray);
}
free(fh);
free(fi);
free(fq);
fclose(fpBMP);
fclose(fpGray);
printf("success\n");
return 0;
}