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