BMP文件是Windows操作系统所推荐和支持的图像文件格式,是一种将内存或显示器的图像数据不经过压缩而直接按位存盘的文件格式,所以称为位图(bitmap)文件。
BMP文件结构
BMP图像文件包括四个部分:
1、位图文件头(Bitmap File Header)
2、位图信息头(Bitmap Info Header)
3、颜色表(Color Map)
4、图像数据(即图像数据,Data Bits)
一、位图文件头,是一个结构体类型,长度固定为14个字节。定义如下:
typedef unsigned char LBYTE;
typedef unsigned short LWORD;
typedef unsigned int LDWORD;
typedef long LLONG;
typedef struct
{
LWORD bfType; //位图文件类型,必须是0X4D42
LDWORD bfSize; // 位图文件大小
LWORD bfReserved1; //windows保留字
LWORD bfReserved2; //windows保留字,暂时不用
LDWORD bfOffBits; //从文件头到实际的位图数据的偏移字节数
}LBITMAPFILEHEADER;
二、位图信息头
typedef struct
{
LDWORD biSize; //位图信息头的长度,40字节
LLONG biWidth; //位图的宽度
LLONG biHeight; //位图的高度
LWORD biPlanes; //目标设备级别,必须为1
LWORD biBitCount; // 每个像素所占位数(bit),二值图像为1,灰度图像为8,真彩色图像为24
LDWORD biCompression; // 位图压缩类型
LDWORD biSizeImage; // 实际的位图数据占用的字节数
LLONG biXPelsPerMeter; //指定目标设备的水平分辨率
LLONG biYPelsPerMeter; //指定目标设备的垂直分辨率
LDWORD biClrUsed; // 位图实际用到的颜色数
LDWORD biClrImportant; // 位图显示过程中重要的颜色数
}LBITMAPINFOHEADER;
三、颜色表
颜色表也是一个结构体类型,实际上是一个颜色表结构的数组,数组的长度由biClrUsed指定。其中有些位图需要颜色表,如灰度图;有些位图不需要颜色表,如真彩色图。
typedef struct
{
LBYTE rgbBlue; //蓝色分量
LBYTE rgbGreen; //绿色分量
LBYTE rgbRed; //红色分量
LBYTE rgbReserved; //保留字节,暂时不用
}LRGBQUAD;
四、位图数据
位图数据也就是图像数据,紧跟在位图文件头,位图信息头和颜色表之后,记录了图像的每一个像素值。
需要注意的是,windows规定一个扫描行所占的字节数必须是4的倍数,不足4的倍数则要对其进行扩充。则每个扫描行所占的真实字节数的计算结果为:int lineByte = (imWidth * biBitCount / 8 + 3)/ 4 * 4;
现在是保存图像数据的时候,这里我保存的是灰度图像的数据,所以直接设置biBitCount的值为8。大家可以根据自己的需求进行修改。saveBMP.cpp的代码如下:
#include "StdAfx.h"
#include"bmp.h"
#include<iostream>
using namespace std;
bool SaveBmp1(char * fileName,unsigned char *imgBuffer, int imWidth, int imHeight)
{
if (!imgBuffer)
{
return 0;
}
int biBitCount = 8;
int colorTablesize = 1024; //灰度图像颜色表
int lineByte = (imWidth * biBitCount / 8 + 3)/ 4 * 4;
FILE *fp = fopen(fileName, "wb");
if (!fp)
{
return 0 ;
}
LBITMAPFILEHEADER filehead;
filehead.bfType = 0x4D42;
filehead.bfSize = sizeof(LBITMAPFILEHEADER) + sizeof(LBITMAPINFOHEADER) +
colorTablesize + lineByte * imHeight;
filehead.bfReserved1 = 0;
filehead.bfReserved2 = 0;
filehead.bfOffBits = 54 + colorTablesize;
//写位图文件头进文件
fwrite(&filehead , sizeof(LBITMAPFILEHEADER), 1, fp);
//申请位图文件信息头结构变量, 填写文件信息头信息
LBITMAPINFOHEADER infoHead;
infoHead.biBitCount = biBitCount;
infoHead.biClrImportant = 0;
infoHead.biClrUsed = 0;
infoHead.biSize = 40;
infoHead.biWidth = imWidth;
infoHead.biHeight = imHeight;
infoHead.biPlanes = 1;
infoHead.biCompression = 0;
infoHead.biSizeImage = lineByte * imHeight;
infoHead.biXPelsPerMeter = 0;
infoHead.biYPelsPerMeter = 0;
fwrite(&infoHead, sizeof(LBITMAPINFOHEADER), 1, fp);
//fwrite(&filehead, sizeof(LBITMAPFILEHEADER), 1, fp);
LRGBQUAD *pColorTable = new LRGBQUAD[256];
for (int i = 0 ; i < 256 ; i++)
{
pColorTable[i].rgbBlue = i;
pColorTable[i].rgbGreen = i;
pColorTable[i].rgbRed = i;
//pColorTable[i].rgbReserved = 0;
}
fwrite(pColorTable, sizeof(LRGBQUAD), 256, fp);
//写位图数据进文件
fwrite(imgBuffer, imHeight*lineByte, 1, fp);
fclose(fp);
return 1;
}
bmp.h代码如下:
#ifndef BMP_H
#define BMP_H
typedef unsigned char LBYTE; //
typedef unsigned short LWORD; //
typedef unsigned int LDWORD;
typedef long LLONG; //
//
#pragma pack(2)
typedef struct
{
LWORD bfType;
LDWORD bfSize;
LWORD bfReserved1;
LWORD bfReserved2;
LDWORD bfOffBits;
}LBITMAPFILEHEADER;
// #pragma pack(pop)
typedef struct
{
LDWORD biSize;
LLONG biWidth;
LLONG biHeight;
LWORD biPlanes;
LWORD biBitCount;
LDWORD biCompression;
LDWORD biSizeImage;
LLONG biXPelsPerMeter;
LLONG biYPelsPerMeter;
LDWORD biClrUsed;
LDWORD biClrImportant;
}LBITMAPINFOHEADER;
typedef struct
{
LBYTE rgbBlue;
LBYTE rgbGreen;
LBYTE rgbRed;
LBYTE rgbReserved;
}LRGBQUAD;
typedef struct
{
unsigned char* buf;
int width_x;
int height_y;
int deepth;
LRGBQUAD* palette;
}LBmpbase;
//bool saveBmp(char*, unsigned char*, int, int, int, RGBQUAD*);
//Bmpbase readbmp(char*);
bool saveBmp(char*, unsigned char*, int, int, int, LRGBQUAD* );
bool SaveBmp1(char * fileName,unsigned char *imgBuffer, int imWidth, int imHeight);
bool wDataToBitBmp(BYTE*, int imWidth, int imHeight, char *imName);
// Bmpbasel readbmp(char*);
// Bmpbase imrotate(unsigned char*, int, int, int, RGBQUAD*, double);
#endif
下面是我调用SaveBmp1的实例:
SaveBmp1((char *)(LPCTSTR)(strFileName1), pBmpImage, 640, 512);
//strFileName1 为保存的bmp格式图像的图像名, pBmpImage为 unsigned char * 类型的图像数据, 640,512分别为图像宽和高。