分享

用C语言写BMP图像文件

 yyy2k3 2012-08-08

用C语言写BMP图像文件

网上很多关于如何加载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文件,就遇到了这个问题,采取上述办法解决

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多