网上很多关于如何加载bmp图像文件的程序,关于如何生成bmp文件确比较少,来补充这个空白吧
输出bmp图像,首先要了解bmp的文件结构,这个谷歌一下有很多资料,简单说由三部分构成
1.文件头tagBITMAPFILEHEADER
2.信息头tagBITMAPINFOHEADER
3.颜色表tagRGBQUAD (可以省略这个结构)
由于一会不使用这个结构, 先简单介绍下,以上两个结构体在程序中详细介绍
如下:
typedef struct tagRGBQUAD {
BYTErgbBlue; // 蓝色的亮度(值范围为0-255)
BYTErgbGreen; // 绿色的亮度(值范围为0-255)
BYTErgbRed; // 红色的亮度(值范围为0-255)
BYTErgbReserved; // 保留,必须为0
} RGBQUAD;
颜色表中RGBQUAD结构数据的个数有biBitCount来确定:
当biBitCount=1, 4, 8时,分别有2,16,256个表项;
当biBitCount=24时,没有颜色表项。(本程序生成的是24位真彩图,所以不需要定义颜色表项)
位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下:
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader; // 位图信息头
RGBQUAD bmiColors[1]; // 颜色表
} BITMAPINFO;
※※※※
准备工作完了,下面进入正题
bmpwin.c
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
/*位图头文件数据结构*/
typedef struct tagBITMAPFILEHEADER {
unsigned char bfType[2]; //位图文件类型,必须为'B' 'M'
unsigned long bfSize; //位图文件大小(以字节为单位)
unsigned short bfReserved1; //位图文件保留字,必须为0
unsigned short bfReserved2; //位图文件保留字,必须为0
unsigned long bfOffBits; //位图数据的起始位置,以相对位图文件头的偏移量(单位字节)
}BITMAPFILEHEADER ; //共14Byte
/*位图信息数据结构*/
typedef struct tagBITMAPINFOHEADER{
unsigned long biSize; //本结构所占用字节数
long biWidth; //位图宽度,以像素为单位
long biHeight; //位图高度,以像素为单位
unsigned short biPlanes; //目标设备级别,必须为1
unsigned short biBitCount; //每个像素所需的位数,1(双色),4(16色),8(256色),24(真彩色)
unsigned long biCompression; //位图的压缩类型,必须是0(示不压缩),1(BI_RLE8压缩类型),2(BI_RLE4压缩类型)之一
unsigned long biSizeImage; //位图大小以字节为单位
long biXPixPerMeter; //图像水平分辨率,每米像素数
long biYPixPerMeter; //图像垂直分辨率,每米像素数
unsigned long biClrUsed; //位图实际使用的颜色表中的颜色数
unsigned long biClrImporant; //位图显示过程中重要的颜色数
}BITMAPINFOHEADER; //共40Byte
int main(void)
{
FILE *fp;
int i,j;
unsigned char c, d;
BITMAPFILEHEADER *bitmapFileHeader;
BITMAPINFOHEADER *bitmapInfoHeader;
if((fp=fopen("f://234.bmp", "wb")) = =NULL){
fprintf(stderr, "file cannot open\n");
exit(1);
}
/* 结构体指针初始化 */
bitmapFileHeader=(BITMAPFILEHEADER *)malloc(sizeof(BITMAPFILEHEADER));
bitmapInfoHeader=(BITMAPINFOHEADER *)malloc(sizeof(BITMAPINFOHEADER));
printf("%d\n",sizeof( bitmapFileHeader->bfType[2]));
/*定义位图头文件数据结构*/
bitmapFileHeader->bfType[0] = 'B';
bitmapFileHeader->bfType[1] = 'M';
bitmapFileHeader->bfReserved1 = 0x0000;
bitmapFileHeader->bfReserved2 = 0x0000;
//位图起始位置
bitmapFileHeader->bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
/*定义位图信息数据结构*/
bitmapInfoHeader->biSize = sizeof(BITMAPINFOHEADER);
bitmapInfoHeader->biWidth = (long)128;
bitmapInfoHeader->biHeight = (long)128;
bitmapInfoHeader->biPlanes = 0x0001;
bitmapInfoHeader->biBitCount = 0x0018; //24位图
bitmapInfoHeader->biCompression = 0x0000; //不压缩
/*每像素由RGB24位构成,即3字节*/
bitmapInfoHeader->biSizeImage = bitmapInfoHeader->biWidth*bitmapInfoHeader->biHeight * 3;
bitmapInfoHeader->biXPixPerMeter = 3780; /*96dpi*/
bitmapInfoHeader->biYPixPerMeter = 3780; /*96dpi*/
bitmapInfoHeader->biClrUsed = 0;
bitmapInfoHeader->biClrImporant = 0;
/*位图文件大小*/
bitmapFileHeader->bfSize = bitmapFileHeader->bfOffBits + bitmapInfoHeader->biSizeImage;
/*位图头文件结构写入文件*/
fwrite((unsigned char *)bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, fp);
/*位图信息结构写入文件*/
fwrite((unsigned char *)bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, fp);
/*RGB颜色写入文件*/
for(j=0;j<bitmapInfoHeader->biHeight;j++){
for(i=0;i<bitmapInfoHeader->biWidth;i++){
c=(((i&0x08)==0)^((j&0x08)==0))*255;
fputc(c, fp); /* B */
fputc(c, fp); /* G */
fputc(c, fp); /* R */
}
}
free(bitmapFileHeader);
free(bitmapInfoHeader);
fclose(fp);
return 0;
}
本程序在VS2010下编译通过,生成图像如图
如果编译成功,但是生成图像打不开,很有可能是在图片的结构信息写入文件时候出现错误,fwrite()函数在将结构体写入文件的时候,如果数据总大小sizeof(BITMAPINFOHEADER) 大于结构体中成员变量大小的和的话(即结构体内存对齐现象),可能会写入错误。
这个时候可以借助软件UltraEdit或Editplus等工具软件以16进制的方式打开图片,会看到有“CD”字样,如图红色标记部分
这是我能想到的算是debug的一种方式吧~~
要说明的是 这个程序在VS2010编译时,结构体struct tagBITMAPFILEHEADER 竟然没有出现内存对齐的现象,也就是sizeof(struct tagBITMAPFILEHEADER )结果是14,上网查了原因好像是说修改了内存对齐设置之类的(至今还不明白~~)
如果sizeof(struct tagBITMAPFILEHEADER )的结果是16的话,直接用 fwrite((unsigned char *)bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, fp); 就会出现写入错误。
例如结构体
typedef struct tagBITMAPFILEHEADER {
unsigned char bfType[2]; //位图文件类型,必须为'B' 'M'
unsigned long bfSize; //位图文件大小(以字节为单位)
unsigned short bfReserved1; //位图文件保留字,必须为0
unsigned short bfReserved2; //位图文件保留字,必须为0
unsigned long bfOffBits; //位图数据的起始位置,以相对位图文件头的偏移量(单位字节)
}BITMAPFILEHEADER ; //共14Byte
unsigned long bfOffBits; 的偏移量是10,不是4的倍数需要补齐到12,这样结构体的大小是16,此时直接 fwrite((unsigned char *)bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, fp); 就会出现写入错误,编译虽然通过了,但是图像文件的格式不对,打不开(可以查看图像对应的16进制码检验)
解决方法:我能想到的一个比较笨的办法(毕竟是初学者,没什么高级办法)。分段写入文件,
即fwrite(&bfReserved2, sizeof(bfReserved2), 1, fp);
fwrite(&bfOffBits; , sizeof(bfOffBits), 1, fp);
这样写入文件就可以了。
下一篇文章将介绍生成TGA文件,就遇到了这个问题,采取上述办法解决