opengl保存数据为bmp文件



首先了解一下BMP文件的格式,在网上也能找到很多的相关资料。
位图的格式可用下面的结构来表示:
  a、BITMAPFILEHEADER bmfh;
  b、BITMAPINFOHEADER bmih;
  c、RGBQUAD aColors[];
  d、BYTE aBitmapBits[];


  A、第一部分为位 图文件头BITMAPFILEHEADER,是一个结构,其定义如下:
  typedef struct tagBITMAPFILEHEADER{
  unsigned short bfType;    2Bytes 指定文件类型,必须是42 4D,即字符串"BM"
  unsigned int bfSize;         4Bytes 指定文件大小,包括这14 个字节
  unsigned short bfReserved1; 2Bytes 为保留字,填充 00 00
  unsigned short bfReserved2;2Bytes 为保留字,填充 00 00
  unsigned int bfOffBits;   4Bytes 为从文件头到实际的位图数据的偏移字节数
  } BITMAPFILEHEADER; //这个结构的长度为14 个字节 这一点很重要
  
      之前可以用Windows自带的画图程序,画一个 600*400的BMP图像 test.bmp
  在LINUX下用命令 od -x test.bmp >> test
      vi test
      可以看到头14 个字节为:
  42 4D | 36 00 12 00 | 00 00 | 00 00 | 36 00 00 00


   
  B、第二部分为位图信息头BITMAPINFOHEADER,也是一个结构,
      其定义如下
  typedef struct tagBITMAPINFOHEADER{
  unsigned int biSize;
  int biWidth;
   int biHeight;
  unsigned short biPlanes;
  unsigned short biBitCount;
  unsigned int biCompression;
  unsigned int biSizeImage;
  int biXPelsPerMeter;
  int biYPelsPerMeter;
   unsigned int biClrUsed;
  unsigned int biClrImportant;
  } BITMAPINFOHEADER;//这个结构的长度为40 个字节,


      各个域的说明如下:
  biSize 4Bytes 指定这个结构的长度,为0x28(40)个字节
  biWidth 4Bytes 指定图象的宽度,单位是象素
    biHeight 4Bytes 指定图象的高度,单位是象素
  biplanes 2Bytes 必须是1
   biBitCount 2Bytes 指定表示颜色时要用到的位数,常用的值为
      1: 黑白二色图;
      4: 16 色图;
      8: 256 色图;
      24: 24 位真彩色图(新的.bmp 格式支持32 位色)。


   BiCompression 4Bytes 指定位图是否压缩,有效的值为
     BI_RGB = 0,不压缩
     BI_RLE8 = 1,RLE8 压缩
     BI_RLE4 = 2,RLE4 压缩
     BI_bitfields = 3


    BiSizeImage 4Bytes 指定实际的位图数据占用的字节数,其实也可以从以下的公式
  中计算出 来:biSizeImage=biWidth'*biHeight
(要注意的是:上述公式中的biWidth'必须是4 的整倍数(所以不是biWidth,而是biWidth',
表示大于或等于biWidth 的4 的整倍数。举个例子,如果biWidth=240,则biWidth'=240;
如果 biWidth=241,biWidth'=244)如果biCompression 为BI_RGB,则该项可能为零


  biXPelsPerMeter 4Bytes 指定目标设备的水平分辨率,单位是每米的象素个数
  biYPelsPerMeter 4Bytes 指定目标设备的垂直分辨率,单位是每米的象素个数
  biClrUsed 4Bytes 指定本图象实际用到的颜色数,如果该值为零,则用到的颜色数为2 的biBitCount 次方
     biClrImportant 4Bytes 指定本图象中重要的颜色数,如果该值为零,则认为所有的颜色都是重要的
  
  vi test 
      可以看到这40 个字节的值。
  
  C、第三部分为调色板(Palette),
当然,这里是对那些需要调色板的位图文件而言的。有些位图,如24真彩色图,前面已经讲过,是不需要调色板的,BITMAPINFOHEADER 后直接是位图数据。
  调色板实际上是一个数组,共有biClrUsed 个元素(如果该值为零,则有2 的biBitCount次方个元素)。数组中每个元素的类型是一个RGBQUAD 结构,占4 个字节,其定义如下:
  typedef struct tagRGBQUAD{
  BYTE rgbBlue; //该颜色的蓝色分量
  BYTE rgbGreen; //该颜色的绿色分量
   BYTE rgbRed; //该颜色的红色分量
  BYTE rgbReserved; //保留值
  } RGBQUAD;


   D、第四部分就是实际的图象数据了。对于用到调色板的位图,图象数 据就是该像素颜色在调色板中的索引值,对于真彩色图,图象数据就是实际的 R,G,B 值。下面就2 色,16 色,256 色位图和真彩色位图分别介绍。
  对于2 色位图,用1 位就可以表示该像素的颜色(一般0 表示黑,1 表示白),所以一个字节可以表示8 个像素。
  对于16 色位图,用4 位可以表示一个像素的颜色,所以一个字节可以表示2 个像素。
  对于256 色位图,一个字节刚好可以表示1 个像素。
  对于真彩色 图,三个字节才能表示1 个像素。


  E、图象数据的注意事项
  1、 图象数据的字节数必须是4 的整倍数,如果不是,则需要补齐。这在前面介绍biSizeImage 时已经提到了,使用索引色时位图中每行的数据也必须为4 个字节。2、BMP 文件的数据从下到上,从左到右的。也就是说,从文件中最先读到的是图象最下面一行的左边第一个像素,然后是左边第二个像素⋯接下来是倒数第二行左边第一个 像素,左边第二个像素⋯依次类推,最后得到的是最上面一行的最右一个像素。


  实现保存24 位真彩色位图 我的最终代码


#include "stdio.h"
#include "stdlib.h"

#define  w 10

#define h 10



typedef long LONG;
typedef unsigned char BYTE;
typedef unsigned int DWORD;
typedef unsigned short WORD;




typedef struct {
        WORD    bfType;
        DWORD   bfSize;
        WORD    bfReserved1;
        WORD    bfReserved2;
        DWORD   bfOffBits;
} BMPFILEHEADER_T;


typedef struct{
        DWORD      biSize;
        DWORD       biWidth;
        DWORD       biHeight;
        WORD       biPlanes;
        WORD       biBitCount;
        DWORD      biCompression;
        DWORD      biSizeImage;
        DWORD       biXPelsPerMeter;
        DWORD       biYPelsPerMeter;
        DWORD      biClrUsed;
        DWORD      biClrImportant;
} BMPINFOHEADER_T;


void Snapshot( BYTE * pData, int width, int height,  char * filename ,DWORD size)
{


      // 位图第一部分,文件信息
       BMPFILEHEADER_T bfh={0};
       bfh.bfType = (WORD)0x4d42;  //bm
       bfh.bfSize = (DWORD)(size+54);
       bfh.bfReserved1 = 0; // reserved
       bfh.bfReserved2 = 0; // reserved
       bfh.bfOffBits = 54;
       // 位图第二部分,数据信息
       BMPINFOHEADER_T bih={0};
       bih.biSize = 40;
       bih.biWidth = width;
       bih.biHeight = height;
       bih.biPlanes = 1;
       bih.biBitCount = 24; //24真彩色位图
       bih.biCompression = 0;
       bih.biSizeImage = 0;
       bih.biXPelsPerMeter = 0;
       bih.biYPelsPerMeter = 0;
       bih.biClrUsed = 0;
       bih.biClrImportant = 0;


       FILE * fp = fopen(filename,"wb");
       if( !fp ) return;
       fwrite( &bfh.bfType,1,2,fp );
       fwrite( &bfh.bfSize,1,4,fp );
       fwrite( &bfh.bfReserved1,1,2,fp );
       fwrite( &bfh.bfReserved2,1,2,fp );
       fwrite( &bfh.bfOffBits,1,4,fp );
//这里一定要特别注意,如果使用 fwrite( &bih,1,sizeof(BMPFILEHEADER_T),fp );因为头信息是14位,使用这个语句填充的是16位,图像显示的是黑色的。所以要按照位数填充,以免自动补齐,这个问题也是我通过对比正确的BMP文件 和我生成的bmp文件的二进制格式位数,发现前面几位就是错位的,网上很多资料写的都实现不了,不知道是什么问题。


       fwrite( &bih,1,sizeof(BMPINFOHEADER_T),fp );
       fwrite(pData,1,size,fp);
       fclose( fp );


}
// 位图第二部分,数据信息
void SaveFile()
{


    unsigned char *bits;//定义指向位图数据的指针
    DWORD size=4*((w*24+31)/32) * h; //也是为了保证是四的倍数
    bits = (unsigned char *)malloc(size);//为位图分配内存空间并赋值给bits
    glReadPixels(0,0,w,h,GL_BGR_EXT,GL_UNSIGNED_BYTE,bits);//从帧缓存中读取位图数据
    Snapshot(( BYTE*)bits,w,h,"test.bmp",size);// 生成24位BMP图片
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值