windows程序设计之DIB操作

主要介绍下与设备无关的位图DIB(Device Independent Bitmap)
位图的基本格式
1.文件头
typedef struct tagBITMAPFILEHEADER {
WORD bfType;//bmp图类型为'BM'或者0X4D42
DWORD bfSize;//整个文件大小
WORD bfReserved1;//0
WORD bfReserved2;//0
DWORD bfOffBits;//DIB像素数据偏移
} BITMAPFILEHEADER
2.信息头
typedef struct tagBITMAPINFOHEADER{
DWORD biSize;//结构体大小 = 40
LONG biWidth;//文件宽度(像素)
LONG biHeight;//文件高度(像素)
WORD biPlanes;//1
WORD biBitCount;//每像素位数(1,4,8,16,24,32)
DWORD biCompression;//压缩方式
DWORD biSizeImage;//实际位图数据占用的字节数
LONG biXPelsPerMeter;//X方向分辨率
LONG biYPelsPerMeter;//Y方向分辨率
DWORD biClrUsed;//使用的颜色数
DWORD biClrImportant;//重要颜色数
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;
biBitCount字段
$ 1(2色DIB)
$ 4(16色DIB)
$ 8(256色DIB)
$ 24(全色DIB)

3.RGB色彩表(不一定有)
对于像素位(biBitCount字段)是1,4,和8时,BITMAPINFOHEADER后面跟着的是色彩表。
typedef struct tagRGBQUAD {
BYTE rgbBlue;//蓝色
BYTE rgbGreen;//绿色
BYTE rgbRed;//红色
BYTE rgbReserved;//保留,0
} RGBQUAD;

每个像素点都是一个RGB,三种色彩组成颜色。要注意的就是里面的元素顺序是BGR。

4.位图像素位
这里才是图像数据的真实存放处,可以在这里读取图像的数据进行操作。每个像素点都是由RGB数组构成。要注意的是,在DIB中,图像的底行是文件的第一行,图像的顶行是文件的最后一行。但是对于同一行来说,还是从左到右存放数据的。windows程序设计上是这样说的:从下到上DIB的原点是位图图像的左下角,它是图像的第一行的第一个像素。从上到下DIB的原点也是位图图像的左下角,但是这种情况下,左下角是位图数据的最后一行的第一个像素。
DIB中的行数是BITMAPINFOHEADER结构中的biHeight字段,每一行的像素是该结构中biWidth字段,每一行从左边开始,向右数,每个像素位数由bcBitCount确定。
每行的长度必须是4的倍数。
RowLength = 4 * ((bmch.bcWidth * bmch.bcBitCount + 31) / 32)计算;

总的像素位数据大小 = RowLength *bmch.biHeight计算。
下面是对DIB文件的读写:

/****************************************************************************
*函数名称: ReadBmp()
*函数参数: const char *bmpName 写入bmp格式文件的名称及路径
***************************************************************************/
bool ReadBmp(const char *strFile)
{
BITMAPFILEHEADER bitHead;
BITMAPINFOHEADER bitInfoHead;
FILE* pfile;

pfile = fopen(strFile,"rb");//打开文件

if(pfile!=NULL)
{
printf("file bkwood.bmp open success.n");
//读取位图文件头信息
fread(&bitHead,1,sizeof(BITMAPFILEHEADER),pfile);
//fseek(pfile,2,SEEK_CUR); // "BM"
if(bitHead.bfType != 0x4d42)
{
printf("file is not .bmp file!");
return false;
}
//读取位图信息头信息
fread(&bitInfoHead,1,sizeof(BITMAPINFOHEADER),pfile);
}
tagRGBQUAD *pRgb ;
int width = bitInfoHead.biWidth;
int height = bitInfoHead.biHeight;
//分配内存空间把源图存入内存
int l_width = 4 * ((width* bitInfoHead.biBitCount+31) /32);//计算位图的实际宽度并确保它为32的倍数
BYTE *pColorData=(BYTE *)malloc(height*l_width);
memset(pColorData,0,height*l_width);
long nData = height*l_width;

//把位图数据信息读到数组里
fread(pColorData,1,nData,pfile);
fclose(pfile);
return true;
}

/****************************************************************************
*函数名称: saveBmp()

unsigned char *imgBuf 待存盘的位图数据
int width, 以像素为单位待存盘的位图宽
int height, 以像素为单位待存盘的位图高
int biBitCount, 每个像素占的位数
RGBQUAD *pColorTable 颜色表指针
*函数返回值:0为失败 1为成功
*函数描述:给定写入bmp文件的名称和路径 要写入图像的位图数据,宽,高,写进文件中
*
***************************************************************************/
bool saveBmp(const char* bmpName,unsigned char *imgBuf,int width,int height,int biBitCount,RGBQUAD *pColorTable)
{
if(!imgBuf)//imgBuf 待存盘的位图数据
return 0;

int colorTablesize = 0;
if(biBitCount == 8)
colorTablesize =1024;

int lineByte = (width * biBitCount/8+3)/4*4; //行的长度。以字节为单位的每行长度始终是4的倍数

FILE *fp = fopen(bmpName,"wb");
if(fp == 0) return 0;

BITMAPFILEHEADER fileHead; //文件头
fileHead.bfType= 0x4d42; //确保是bmp图像:"BM"
fileHead.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER) + colorTablesize + lineByte *height; //图像大小
fileHead.bfReserved1 = 0;
fileHead.bfReserved2 = 0;
fileHead.bfOffBits = 54 +colorTablesize;

fwrite(&fileHead,sizeof(BITMAPFILEHEADER),1,fp); //写图像文件头

BITMAPINFOHEADER head; //信息头
head.biBitCount = biBitCount; //每像素的位数
head.biClrImportant = 0;
head.biClrUsed = 0;
head.biCompression = 0;
head.biHeight = height; //图像高度
head.biPlanes =1;
head.biSize = 40;
head.biSizeImage = lineByte *height; //图像字节数
head.biWidth = width; //图像高度
head.biXPelsPerMeter = 0;
head.biYPelsPerMeter = 0;

fwrite(&head,sizeof(BITMAPINFOHEADER),1,fp); //写图像文件信息头

if(biBitCount == 8) //如果是8bits,写入色彩表
fwrite(pColorTable,sizeof(RGBQUAD),256,fp);

fwrite(imgBuf,height * lineByte,1,fp); //写图像的数据内容
fclose(fp);
return 1;
}

标签:SDK