您的位置:首页 > 其它

BMP图片格式C函数说明

2014-09-18 16:50 211 查看
 
位图文件格式说明
位图文件由三部分组成:文件头,位图信息,位图像素数据。
   
一、文件头
typedef   struct   tagBITMAPFILEHEADER   {  
          WORD         bfType;    
          DWORD       bfSize;    
          WORD         bfReserved1;    
          WORD         bfReserved2;    
          DWORD       bfOffBits;    
}   BITMAPFILEHEADER;  
 
bfType:文件类型。在 BMP 格式下,始终是“BM”。
bfSize:文件大小,计算方法是:
位图文件头大小【sizeof(BITMAPFILEHEADER)】 +
位图信息头大小【pbih->biSize】 +
颜色表大小【pbih->biClrUsed*sizeof(RGBQUAD)】 +
位图数据大小【pbih->biSizeImage】
bfReserved1:预留字段,为0。
bfReserved2:预留字段,为0。
bfOffBits:图象数据的偏移量,计算方法是:
位图文件头大小【sizeof(BITMAPFILEHEADER)】 +
位图信息头大小【pbih->biSize】 +
颜色表大小【pbih->biClrUsed*sizeof(RGBQUAD)】
 
二、位图信息
位图信息也是由两部分组成的:位图信息头   +   颜色表
 
typedef   struct   tagBITMAPINFO   {  
          BITMAPINFOHEADER         bmiHeader;  
          RGBQUAD                 bmiColors[255];  
}   BITMAPINFO;  
 
bmiHeader:位图信息头,见下面的结构体说明。
bmiColors: RGB颜色表数组。一般不存储到位图,在GetDIBits时将丢失这个信息,biClrUsed将被设置为0。
 
一个位图信息的结构,被分成了 2 个部分,
第一个是 一个 40 Byte 的位图信息头结构,
第二个部分需要根据位图信息头的内容才能确定它究竟是什么。
如果是真彩色(一个像素点需要24bit来表示),这个部分直接表示像素点,
如果是调色板模式,它被分成调色板条目和像素调色板索引 2 个部分。
 
2.1位图信息头。
typedef   struct   tagBITMAPINFOHEADER{   
          DWORD     biSize;    
          LONG       biWidth;    
          LONG       biHeight;    
          WORD       biPlanes;    
          WORD       biBitCount    
          DWORD     biCompression;    
          DWORD     biSizeImage;    
          LONG       biXPelsPerMeter;    
          LONG       biYPelsPerMeter;    
          DWORD     biClrUsed;    
          DWORD     biClrImportant;    
}   BITMAPINFOHEADER;    
biSize:结构BITMAPINFOHEADER的字节数
biWidth:以像素为单位的图像宽度
biHeight:以像素为单位的图像长度
biplanes:调色板数目,一般是1 
biBitCount:像素的位数
biCompression: 图像的压缩格式:
BI_RGB:无压缩
BI_RLE8:8位RLE压缩
BI_RLE4:4位RLE压缩
biSizeImage:  以字节为单位的图像数据的大小,如无压缩,可设为0.计算方法是:
位图宽度象素数目转换成字节   【 ( pbmi->bmiHeader.biWidth + 7 ) / 8 】*

位图高度象素数目【pbmi->bmiHeader.biHeight】* 
象素位数【cClrBits】
biXPelsPermeter:水平方向上的每米的像素个数
biYpelsPerMeter:垂直方向上的每米的像素个数
biClrused : 调色板中实际使用的颜色数,在24位以下时需要使用,计算方法
if(cClrBits < 24)
pbmi->bmiHeader.biClrUsed=(1<<cClrBits)
biClrImportant:   实现位图时必须的颜色数    
注:宽度象素数目+7再除以8,用来处理余数的情况,如位图宽度为2,除以8为0,所以要+7再除以8。
 
2.2 颜色表
typedef   struct   tagRGBQUAD   {     
          BYTE         rgbBlue;    
          BYTE         rgbGreen;    
          BYTE         rgbRed;    
          BYTE         rgbReserved;    
}   RGBQUAD;  
rgbBlue    指定蓝色强度
rgbGreen   指定绿色强度
rgbRed     指定红色强度
rgbReserved保留值,设为0
一个颜色信息结构,整个结构占用32bit
其中需要注意的是,RGBQUAD结构中的颜色顺序是BGR,而不是平常的RGB。    
16位和16位以上的图像,其位图像素数据中直接对对应像素的RGB(A)颜色进行描述。而对于16位以下的图像,由于其位图像素数据中记录的只是调色板索引值,因而需要根据这个索引到调色板去取得相应的RGB(A)颜色。颜色表的作用就是创建调色板。
 
三、位图像素数据
24位位图图象数据的存储是RGB序列,在windows中是BGR序列:

象素B蓝色分量值
象素G绿色分量值
象素R红色分量值
32位位图象素数据的存储是RGBA序列,A是Alpha值,windows是BGRA序列:

象素B蓝色分量值
象素G绿色分量值
象素R红色分量值
象素alpha分量值
16位图象的分布是:

最高位保留,为0
高5位,红色分量
中间5位,绿色分量
最低5位,蓝色分量
紧跟在颜色表后的是图像数据阵列,图像每一扫描行有连续的字节组成,扫描行由底向上存储,阵列中第一字节为左下角像素,最后一字节为右上角像素。
四、位图文件数据实例分析
  以24位真彩色的BMP位图格式比较常用,以它为讲解的对象。
找一幅 24 位真彩色的位图用 16 进制编辑器将其打开,查看方式切换到以 HEX 方式查看的话,你们就可以看到类似下面这样的数据了。
00000
42
4D
96
61
02
00
00
00
00
00
36
00
00
00
28
00
00010
00
00
04
01
00
00
C8
00
00
00
01
00
18
00
00
00
00020
00
00
60
61
02
00
00
00
00
00
00
00
00
00
00
00
00030
00
00
00
00
00
00
0A
0A
0A
0B
0B
0B
10
10
10
17
00040
17
17
1C
1C
1C
1B
1B
1B
14
14
14
0D
0D
0D
0F
0F
00050
0F
0E
0E
0E
0E
0E
0E
0E
0E
0E
10
10
10
13
13
13
00060
16
16
16
18
18
18
15
15
15
19
19
19
17
17
17
0F
00070
0F
0F
0B
0B
0B
0E
0E
0E
11
11
11
10
10
10
0B
0B
00080
0B
14
14
14
17
17
17
11
11
11
0F
0F
0F
14
14
14
00090
14
14
14
0D
0F
0F
05
0A
0D
09
10
13
10
15
18
0F
24 位真彩色的 BMP 图文件是由三个部分组成的:位图文件头、位图信息头、位图阵列三个部分组成的。
4.1 实例文件头分析
位图文件头共有 14 个字节:
42 4D 为位图的标志。如果转换成 ASCII 码的话就是 BM。
96 61 02 00 这个双字信息代表着位图文件的总字节数,如果把它转换面十进制的话就是( 00026196 ) H= ( 156054 ) D ,也就是这位图文件的大小是 156054 个字节。
00 00 00 00 为保留字。
36 00 00 00 表示位图阵列的起始位置,( 00000036 ) H= ( 54 ) D ,也就是从第 54 个字节起就是这幅图的位图阵列了。
4.2 实例位图信息头分析
位图信息头共占 40 个字节:
28 00 00 00 表示着位图信息头的长度,( 00000028 ) H= ( 40 ) D ,即位图信息头的长度占 40 个字节。
04 01 00 00 表示位图的宽度,( 00000104 ) H= ( 260 ) D 表示位图的宽度为 260 个像素。
C8 00 00 00 表示位图的高度,( 000000C8 ) H= ( 200 ) D 表示位图的高度为 200 个像素。
01 00 表示位图设备级别。
18 00 位图的色彩级别,( 0018 ) H= ( 24 ) D ,即表示 24 位真彩色。
00 00 00 00 表示压缩类型,零表示不压缩。
00 00 00 00 位图阵列表字节数。
00 00 00 00 表示水平分辨率。
00 00 00 00 表示垂直分辨率。
00 00 00 00 表示位图实际使用的颜色表中的颜色变址。
00 00 00 00 表示位图显示过程中被认为重要颜色变址数。
4.3 实例位图像素数据分析
每幅图像是由一个一个的点组成的。在位图阵列里就存放着每一个点的颜色信息。每个像素点是由 3 个字节的数据组成的。也就是我们常用到的 RGB 色彩空间每种颜色占一个字节。每个点的颜色都是由蓝色、绿色、红色这个顺序存储的。点的存储顺序是从左到右从下到上,也就是说第一个点是这幅图的第一列的最后一个点(左下角的那个点),之后是它上面的那个点,就这样由下至上直到第一列的第一个点(左上角的那个点),然后是第二列也是从下至上的顺序。直到写完所有的点。
 
五、位图文件操作
5.1.保存位图为文件
可以将程序中的图象保存为文件,具体代码如下:
 
1. 错误信息函数
void exitWND(LPCTSTR msg)
{
     MessageBox(NULL,msg,"Error",0);
     exit(0);
}
 
2. 建立位图信息结构体函数
PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp)
{
 
     BITMAP bmp;
     if(!GetObject(hBmp,sizeof(BITMAP),&bmp))
         exitWND("Error when get object from hbitmap");
 
     //获取颜色位数
     WORD cClrBits;
     cClrBits=(WORD)(bmp.bmPlanes*bmp.bmBitsPixel);
     if(cClrBits == 1)
         cClrBits=1;
     else if(cClrBits <= 4)
         cClrBits=4;
     else if(cClrBits <= 8)
         cClrBits=8;
     else if(cClrBits <= 16)
         cClrBits=16;
     else if(cClrBits <= 24)
         cClrBits=24;
     else cClrBits=32;
 
     //分配位图信息结构体
     PBITMAPINFO pbmi;
     if(cClrBits != 24)
         pbmi=(PBITMAPINFO)LocalAlloc( LPTR, sizeof(BITMAPINFOHEADER) +sizeof(RGBQUAD) * (1<<cClrBits)  );
     else
         pbmi=(PBITMAPINFO)LocalAlloc(LPTR,sizeof(BITMAPINFOHEADER));

 
     //初始化位图结构体
     pbmi->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
     pbmi->bmiHeader.biWidth=bmp.bmWidth;
     pbmi->bmiHeader.biHeight=bmp.bmHeight;
     pbmi->bmiHeader.biPlanes=bmp.bmPlanes;
     pbmi->bmiHeader.biBitCount=bmp.bmBitsPixel;
     if(cClrBits < 24)
         pbmi->bmiHeader.biClrUsed=(1<<cClrBits);
     //不压缩位图
     pbmi->bmiHeader.biCompression=BI_RGB;
 
     //初始化图象数据大小
     pbmi->bmiHeader.biSizeImage= (pbmi->bmiHeader.biWidth + 7 ) / 8 * pbmi->bmiHeader.biHeight * cClrBits;
 
     //所有的设备颜色都重要
     pbmi->bmiHeader.biClrImportant=0;
     //返回指针
     return pbmi;
}
 
3. 建立位图文件函数
void CreateBMPFile(LPTSTR pszFile,PBITMAPINFO pbi,HBITMAP hBmp,HDC hDC)
{
     PBITMAPINFOHEADER pbih=(PBITMAPINFOHEADER)pbi;
     LPBYTE lpBits;
     lpBits=(LPBYTE)GlobalAlloc(GMEM_FIXED,pbih->biSizeImage);
     if(!lpBits)
         exitWND("error to global alloc memory");
 
     //获取位图图象数据
     GetDIBits(hDC,hBmp,0,(WORD)pbih->biHeight,lpBits,pbi,DIB_RGB_COLORS);
 
     //建立位图文件
     HANDLE hf;
     hf=CreateFile(pszFile,GENERIC_READ|GENERIC_WRITE,
         NULL,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
     if(hf == INVALID_HANDLE_VALUE)
         exitWND("error to create file");
 
     //建立位图文件信息头
     BITMAPFILEHEADER hdr;
     hdr.bfType=0x4d42;
     hdr.bfSize=(DWORD)(sizeof(BITMAPFILEHEADER)+
         pbih->biSize+pbih->biClrUsed*sizeof(RGBQUAD)+
         pbih->biSizeImage);
 
     hdr.bfReserved1=0;
     hdr.bfReserved2=0;
 
     //计算位图数据偏移量
     hdr.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER)+
         pbih->biSize+pbih->biClrUsed*sizeof(RGBQUAD);
     //写入位图文件头
     DWORD wt;
     if(!WriteFile(hf,(LPVOID)&hdr,sizeof(BITMAPFILEHEADER),&wt,NULL))
         exitWND("error when write bitmap file header");
 
     //写入位图信息头
     if(!WriteFile(hf,(LPVOID)pbih,
         sizeof(BITMAPINFOHEADER)+pbih->biClrUsed*sizeof(RGBQUAD),
         &wt,NULL))
 
         exitWND("error when write bitmap info header and RGBquad");
 
     //写入位图数据
     if(!WriteFile(hf,(LPVOID)lpBits,pbih->biSizeImage,&wt,NULL))
         exitWND("error when write data");
     //关闭文件
     if(!CloseHandle(hf))
         exitWND("error when close file handle");
 
     //释放图象数据所占内存
     GlobalFree(lpBits);
}
 
4. 保存位图到文件函数
void SaveBitmapFile(LPTSTR fileName,HWND hWnd,HBITMAP bmp)
{
     PBITMAPINFO pbmi;
     pbmi=CreateBitmapInfoStruct(bmp);
     HDC hdc;
     hdc=GetDC(hWnd);
     CreateBMPFile(fileName,pbmi,bmp,hdc);
     ReleaseDC(hWnd,hdc);
}
 
5.2.从文件加载位图
从文件加载位图,用ReadFile定位文件需要使用OVERLAPPED,展开位图到DC使用StretchDIBits函数。代码如下:
 
2. 从位图文件加载图象函数
HBITMAP LoadBitmapFile(LPCTSTR fileName,HWND hWnd)
{
 
     //打开文件
     HANDLE hf;
     hf=CreateFile(fileName,GENERIC_READ,FILE_SHARE_READ,
         NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);
     if(hf == INVALID_HANDLE_VALUE){
         exitWND("error when open file handle");
         return 0x00;
     }
 
     //展开位图文件到DC
     DWORD read;
 
     //读取文件信息头
     BITMAPFILEHEADER bfh;
     OVERLAPPED olbfh;
     memset(&olbfh,0,sizeof(OVERLAPPED));
     olbfh.Offset=0;
     ReadFile(hf,&bfh,sizeof(bfh),&read,&olbfh);
 
     //读取位图信息
     BITMAPINFO bi;
     OVERLAPPED olbi;
     memset(&olbi,0,sizeof(OVERLAPPED));
     olbi.Offset=sizeof(BITMAPFILEHEADER);
     ReadFile(hf,&bi.bmiHeader,sizeof(bi.bmiHeader),&read,&olbi);
 
     //读取位图数据
     LPBYTE lpBits;
     lpBits=(LPBYTE)GlobalAlloc(GMEM_FIXED,bi.bmiHeader.biSizeImage);
     OVERLAPPED ollpbits;
     memset(&ollpbits,0,sizeof(OVERLAPPED));
     ollpbits.Offset=bfh.bfOffBits;
     ReadFile(hf,lpBits,bi.bmiHeader.biSizeImage,&read,&ollpbits);
 
     //建立和窗口关联的DC
     HDC hdc;
     hdc=GetDC(hWnd);
     HDC mem;
     mem=CreateCompatibleDC(hdc);
 
     //建立和DC关联的位图
     HBITMAP bmp;     bmp=CreateCompatibleBitmap(hdc,bi.bmiHeader.biWidth,bi.bmiHeader.biHeight);
     SelectObject(mem,bmp);
 
     //在DC中展开
     StretchDIBits(mem,
         0,0,bi.bmiHeader.biWidth,bi.bmiHeader.biHeight,
         0,0,bi.bmiHeader.biWidth,bi.bmiHeader.biHeight,
         (LPVOID)lpBits,&bi,DIB_RGB_COLORS,SRCCOPY);
 
     //清理工作
     GlobalFree(lpBits);
     DeleteDC(mem);
     ReleaseDC(hWnd,hdc);
     CloseHandle(hf);
 
     //返回位图对象
     return bmp;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bmp图片格式说明