Windows位图文件格式[转]
位图概述
位图格式
位图文件头
结构包含关于类型,大小以及与设备无关的文件层。
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER {
DWORD biSize; // 大小
LONG biWidth; // 宽度
LONG biHeight; // 高度
WORD biPlanes; // 平面?
WORD biBitCount // 为个数
DWORD biCompression; // 压缩
DWORD biSizeImage; // 图像大小
LONG biXPelsPerMeter; // 每公尺X上的像素
LONG biYPelsPerMeter; // 每公尺Y上的像素
DWORD biClrUsed; // ???
DWORD biClrImportant; // ???
} BITMAPINFOHEADER;
位图信息头
该结构体包含关于与颜色格式相关的设备无关位图。
指定的颜色表内的颜色索引,该索引是在位土内被使用的。如果这个值是零。
如果biClrUsed是非零值且biBitCount值小于16, biClrUsed成员指定实际图形引擎或设备驱动的存取值。
biClrImportant被指定的颜色索引必须显示在位图上。
如果颜色值是零,所有颜色是必须的。
目录
一.位图文件存储格式
位图文件存储格式请参考图1.1。
图1.1 位图文件存储格式
图说明请参考表1.1。
表1.1 位图文件存储格式说明
结构体 |
说明 |
BitmapFileHeader |
位图文件信息头 |
BitmapInfo |
位图信息,由以下两个结构体组成 |
BitmapInfoHeader |
位图信息头 |
RGBQUAD |
颜色表 |
BitmapData |
位图数据 |
二.BitmapFileHeader
typedef struct tagBITMAPFILEHEADER { // bmfh
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
bfType:文件类型,0x4d42,也就是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)】
三.BitmapInfo
typedef struct tagBITMAPINFO { // bmi
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO;
bmiHeader:位图信息头,见下节的结构体说明。
bmiColors:RGB颜色表数组。一般不存储到位图,在GetDIBits时将丢失这个信息,biClrUsed将被设置为0。
四.BitmapInfoHeader
typedef struct tagBITMAPINFOHEADER{ // bmih
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
biSize:结构体大小。
biWidth:位图宽度,象素。对应位图宽度,bmp.bmWidth。
biHeight:位图高度,象素。对应位图高度,bmp.bmHeight。
biPlanes:调色板数目,一般是1。对应位图调色板数目,bmp.bmPlanes。
biBitCount:颜色位数。对应位图bmp.bmBitsPixel。
biClrUsed:使用的颜色数,在24位以下时需要使用,计算方法
if(cClrBits < 24) pbmi->bmiHeader.biClrUsed=(1<<cClrBits);
biSizeImage:图象数据大小,计算方法
位图宽度象素数目转换成字节【(pbmi->bmiHeader.biWidth+7)/8】
*位图高度象素数目【pbmi->bmiHeader.biHeight】
*象素位数【cClrBits】
注:宽度象素数目+7再除以8,用来处理余数的情况,如位图宽度为2,除以8为0,所以要+7再除以8。
五.BitmapData
24位位图图象数据的存储是RGB序列,在windows中是BGR序列:
象素B蓝色分量值 |
象素G绿色分量值 |
象素R红色分量值 |
32位位图象素数据的存储是RGBA序列,A是Alpha值,windows是BGRA序列:
象素B蓝色分量值 |
象素G绿色分量值 |
象素R红色分量值 |
象素alpha分量值 |
16位图象的分布是:
最高位保留,为0 |
高5位,红色分量 |
中间5位,绿色分量 |
最低5位,蓝色分量 |
六.保存位图为文件
可以将程序中的图象保存为文件,具体代码如下:
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);
}
七.从文件加载位图
从文件加载位图,用ReadFile定位文件需要使用OVERLAPPED,展开位图到DC使用StretchDIBits函数。代码如下:
1.错误信息函数
//错误信息
void exitWND(LPCTSTR msg)
{
MessageBox(NULL,msg,"Error",0);
exit(0);
}
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;
}