当前位置:网站首页>VC bmp文件总结
VC bmp文件总结
2022-08-04 22:28:00 【wu_zhiyuan】
vc bmp文件总结
.bmp文件结构(磁盘存储)
分成以下几个部分:
- BITMAP FILEHEADER (BMP 文件头)
- BITMAP INFOHEADER (BMP 文件信息头)
- RGBQUAD (BMP 文件调色板)
- BITMAP DATA (BMP 文件数据)
Windows 中位图有两种格式:
- 设备相关位图 Device Depend Bitmap DDB
- 设备无关位图 Device Independ Bitmap DIB
DDB 设备相关位图格式 ------------ BITMAP+CBitmap+HBITMAP
- BITMAP(C++定义的结构体)
- CBitmap(MFC的位图类)
- HBITMAP(Windows中的位图句柄,HANDLE)
DDB由 BITMAP 数据类型的结构 + 图像数据构成。
注意:因为DDB没有保存位图的调色板(不保存调色板),在不同类设备显示时可能造成完全失真。
DIB 设备无关位图格式 ----------- BITMAPINFO(信息头+调色板)
BITMAP INFOHEADER (信息头) + RGBQUAD (调色板) + BITMAP DATA (文件数据) 三部分构成bmp。
它实际就是BMP文件去掉BITMAP FILEHEADER (BMP 文件头),即一个BITMAPINFO结构后面接上调色板再加上图像数据。
BMP文件的显示 ---- DIB / bit(设备无关位图)
- 首先将BMP读成DIB格式,
- 当显示时直接DIB显示,只要读入BITMAPINFO结构和图像数据即可。
BMP文件的显示 ---- DDB(设备相关位图)
- 首先要先将DIB位图转化为DDB位图,
- 再由MFC的CBitmap类显示。
建议: 统一使用DIB显示(现有异议!!)
统一使用DIB显示,即 BITMAPINFO;//个人意见
不要使用以下:BITMAP(结构体) CBitmap(MFC类) HBITMAP(HANDLE)//个人意见
DIB 和DDB的区别 优缺点
DIB
- DIB不依赖于具体设备,可以用来永久性地保存图象。
- DIB一般是以.BMP文件的形式保存在磁盘中的,有时也会保存在.DIB文件中。
- DIB位图的特点是将颜色信息储存在位图文件自身的颜色表中,应用程序要根据此颜色表为DIB创建逻辑调色板。因此,在输出一幅DIB位图之前,程序应该将其逻辑调色板选入到相关的设备上下文并实现到系统调色板中。例如,一个256色的DIB即可以在真彩色显示模式下使用,也可以在16色模式下使用。
- DIB由于自带颜色表,理论上说在不同的设备上显示时均可按原来的颜色还原显示,或仿真显示,但是很明显颜色表需要消耗一定的存储空间,并且在每次显示时均要对颜色进行处理,因此速度较慢。
DDB依赖于具体设备
- DDB依赖于具体设备,它只能存在于内存中(视频内存或系统内存),
- 其颜色模式必须与特定的输出设备相一致,使用系统调色板。例如,如果当前的显示设备是256色模式,那么DDB必然也是256色的。
- 一般只能载入色彩较简单的DDB位图,对于颜色较丰富的位图,需使用DIB才能长期保存。
- DDB由于直接对颜色位平面进行记录,因此显示速度最快,但是在不同的设备上显示时不能保证颜色的还原。
bmp文件存储详解
| 磁盘(存储,例如:.bmp文件) | bmp存储结构 | bit 结构 | 说明 |
|---|---|---|---|
| 位图文件头 | 位图文件头 BITMAPFILEHEADER | ||
| 位图信息头 | 位图信息头 BITMAPINFOHEADER | BITMAPINFO | 事实上,只有1、4、8位位图才有颜色表项。24位位图没有颜色表项,位图头信息后紧跟位图数据。 |
| 颜色表项 | 颜色表项 RGBQUAD | BITMAPINFO | BITMAPINFO包含BITMAPINFOHEADER 和RGBQUAD |
| 位图图象数据 | 图像数据 | 图像数据 |
位图结构体详解
- BITMAP是个结构,记录了已调入内存的BMP图象的宽高,颜色等信息以及图象数据,与系统当前得显示模式,色深有关。
- HBITMAP是图象句柄,标识一幅已调入内存的BMP图象。
- BITMAPFILEHEADER是BMP文件的文件头结构。
- BITMAPINFOHEADER是位图信息头结构,记录BMP图象本身的宽高,颜色等信息,但不包含图象数据,且与系统显示模式无关。
- BITMAPINFO包含BITMAPINFOHEADER 和 图象数据。
- PBITMAPINFO是BITMAPINFO的指针。
- BITMAPFILEHEADER,BITMAPINFO(包含:BITMAPINFOHEADER和图像数据)是BMP文件用的记录结构,其组成了完整bit文件(设备无关位图)。
- BITMAP,HBITMAP是已调入内存的BMP图象用的,用来操作或得到,修改其信息。(导入内存后,为DDB设备相关位图)
分项详解:
- BITMAPFILEHEADER结构 - 位图文件头
typedef struct tagBITMAPFILEHEADER{
WORD bfType; // 只能是BM,表示位图的ASCII码为BM,其16进制表示为0x4D42
DWORD bfSize; // 表示以字节为单位的文件大小
WORD bfReserved1; // 保留字段,其值均为0
WORD bfReserved2; // 保留字段,其值均为0
DWORD bfOffBits; // 表示从位图文件头开始到位图数据段的字节总数,即字节偏移量
}BITMAPFILEHEADER;
- BITMAPINFOHEADER结构 - 位图信息头
typedef struct tagBITMAPINFOHEADER{
DWORD biSize; // 表示该结构的大小
DWORD biWidth; // 表示以像素为单位的位图宽度
DWORD biHeight; // 表示高度
WORD biPlanes; // 表示目标设备的位平面数,置为1
WORD biBitCount; // 表示位图每个像素的位数,可能为1、4、8、或24
DWORD biCompression; // 表示位图的被压缩类型。若位图未被压缩,则该值为0;若为1,则表示采用RLE(Run Length Encoded)8压缩;若位2,则表示采用RLE4压缩
DWORD biSizeImage; // 表示被压缩位图的字节数
DWORD biXPelsPerMeter; // 表示目标设备的水平分辨率
DWORD biYPelsPerMeter; // 表示目标设备的垂直分辨率
DWORD biClrUsed; // 表示位图实际使用的颜色数
DWORD biClrImportant; // 指对于显示该位图比较重要的颜色索引的个数,若该值尾0,则表示所有的颜色都是重要的
}BITMAPINFODEADER;
- RGBQUAD结构
typedef struct tagRGBQUAD{
BYTE rgbBLUE; // rgbBLUE、 rgbGREEN、rbgRED分别表示蓝、绿、红分量
BYTE rgbGREEN;
BYTE rbgRED;
BYTE rgbReserved; // 值为0
}RGBQUAD;
- BITMAPINFO结构
把BITMAPINFOHEADER结构和一张颜色表结合在一起,其定义如下:
tyepdef struct tagBITMAPINFO{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1]; // 只有1、4、8位位图才有颜色表项。24位位图没有颜色表项,位图头信息后紧跟位图数据。
}BITMAPINFO;
- BITMAP结构
typedef struct tagBITMAP {
LONG bmType; // 指定位图类型;设置为零
LONG bmWidth; // 指定位图的宽度(以像素为单位)。宽度必须大于零。
LONG bmHeight; // 指定位图的高度(以像素为单位)。高度必须大于零。
LONG bmWidthBytes; // 指定每条扫描行中的字节数。此值必须可被 2 整除,因为系统假定位图的位值形成一个与字对齐的数组。
WORD bmPlanes; // 指定颜色平面的计数。
WORD bmBitsPixel; // 指定指示像素颜色所需的位数。
LPVOID bmBits; // 指向位图的位值位置的指针 bmBits 成员必须是指向字符(1 字节)值数组的长指针。
} BITMAP;
BID 图像无关位图详解 - CBitmap、HBITMAP、BITMAP
概念
BITMAP是C++中定义的位图结构体(BID类)
HBITMAP是Windows中使用的位图句柄(BID类)
CBitmap是MFC封装的位图类(BID类)
相互转换
1、HBITMAP->CBitmap
方法一: CBitmap::Attach() 函数
HBITMAP hBitmap=(HBITMAP)::LoadImage(NULL, str, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); // 载入位图
CBitmap bitmap;
bitmap.Attach(hBitmap);
方法二:CBitmap::FromHandle()函数
HBITMAP hBitmap = (HBITMAP)::LoadImage(NULL, str, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); // 载入
CBitmap *bitmap=CBitmap::FromHandle(hBitmap);
注意:Attach和FromHandle的区别
- FromHandle得到的指针是临时变量,通过FromHandle得到的只是暂时的,大概只在一个消息区间内有效,很快便会被删除,所以基本上不能用。我用了FromHandle然后一直出错!!!
- 通过Attach连接的句柄可以长久保留,
实验源码,在(OnPaint函数中添加)
CString str = _T(“E:\picture\lena.bmp”);
HBITMAP hBitmap=(HBITMAP)::LoadImage(NULL, str, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); // 加载硬盘中的位图
CBitmap bitmap;
bitmap.Attach(hBitmap);
CPaintDC dc(this);
CDC MemDC;
MemDC.CreateCompatibleDC(&dc);
MemDC.SelectObject(&bitmap);
CRect rect;
GetClientRect(&rect);
dc.BitBlt(0, 0, rect.Width(), rect.Height(), &MemDC, 0, 0, SRCCOPY);
CBitmap类中的成员函数LoadBitmap:
- BOOL LoadBitmap(LPCTSTR lpszRecourceName); // 加载工程中的位图
- BOOL LoadBitmap(UINT nIDResource); // 加载工程中的位图
两个函数都可以加载位图,但他们只能加载工程中的位图,不能像LoadImage一样,加载硬盘中的位图。
注意:
BOOL LoadBitmap(LPCTSTR lpszRecourceName)函数中的lpszRecourceName不能为路径字符串。它指的是位图的ID是用字符串表示。
错误用法示例:
我在工程中创建了一个位图资源IDB_BITMAP1 ,lpszResourceName是指什么呢,是硬盘上的bitmap1.bmp吗,如果是,以下代码为什么是错的。
CBitmap bmp;
bmp.LoadBitmap(“d:\…\res\bitmpa1.bmp”); // 这里不能是位图在硬盘的路径,而应该是IDB_BITMAP (.rc文件中的位图路径)
CDC memdc;
BITMAP bm;
bmp.GetBitmap(&bm);
memdc.CreateCompatibleDC(pDC);
memdc.SelectObject(&bmp);
pDC->BitBlt(0,0,bm.bmWidth,bm.bmHeight,&memdc,0,0,SRCCOPY);
用Notepad打开*.rc文件,找到类似下面一行:
IDB_BITMAP BITMAP “res\background.bmp”
改成:
Bitmap1 BITMAP “res\background.bmp”
或者,在VC中察看位图资源的属性,将其ID栏内改为"Bitmap"(注意,一定要加引号)。
然后调用:
bmp.LoadBitmap(“Bitmap1”); // 保证成功。
资源可以用一个整数来标示,也可以用一个字符串标示。但无论如何,这些ID都不是指位图文件名。
2、HBITMAP->BITMAP
CString str = _T(“E:\picture\lena.bmp”);
HBITMAP hBitmap = (HBITMAP)::LoadImage(NULL, str, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
BITMAP bm;
::GetObject(hBitmap, sizeof(bm), &bm);
3、CBitmap->BITMAP
CBitmap bitmap;
bitmap.LoadBitmapW(IDB_BITMAP1);
BITMAP bm;
bitmap.GetBitmap(&bm);
4、CBitmap->HBITMAP
方法一:
CBitmap bitmap;
bitmap.LoadBitmapW(IDB_BITMAP1);
HBITMAP hBitmap = (HBITMAP)bitmap.m_hObject;
方法二:
CBitmap bitmap;
bitmap.LoadBitmapW(IDB_BITMAP1);
HBITMAP hBitmap = (HBITMAP)bitmap;
5、BITMAP->HBITMAP
HBITMAP hBitmap;
pbm->GetHBITMAP(NULL, &hBitmap);
6、BITMAP->CBitmap
Bitmap* pBitmap = new Bitmap(width,height,PixelFormat24bppRGB);
HBITMAP hBitmap;
BITMAP bm;
pBitmap ->GetHBITMAP(NULL,&hBitmap);
CBitmap* bmp;
bmp.Attach(hBitmap);
如何把DIB转换成DDB
常用函数
- GetDIBts DDB转换为DIB
- SetDIBts DIB转换为DDB
- CreateDIBitmap 用指定的DIB创建DDB并且初始化位图图像
- CreateDIBSection 创建一个直接可以写入的DIB
CreateDIBitmap 与CreateDIBSection 最主要区别:
CreateDIBitmap创建的是 设备相关位图句柄 - HBITMAP.
CreateDIBSection创建的是 设备无关位图句柄 - HBITMAP.
DIB和 DDB之间的相互转换比较慢(关于DIB与DDB区别详见 《设备相关(DDB)与设备无关(DIB)》 ),所以我们使用CreateDIBSection()来创建一个DIB区块。这样作图速度快。
CreateDIBSection()返回的是一个HBITMAP,CreateDIBitmap()返回的也是HBIT MAP。
两者的区别在于: CreateDIBSection创建的是一个 DIBSECTION结构,
CreateDIBitmap创建的是 BITMAP结构。
关于DIB区块(DIBSECTION)详见: http://technet.microsoft.com/zh-cn/library/aa930771。
可以看到,它包含了一个 位图结构BITMAP,一个DIB信息头BITMAPINFOHEADER,一个掩码表dsBIT fields[3].
还有一个内存映射文件句柄和偏移量。我们不去理睬最后两个字段。
因此,使用GDI函数对 CreateDIBSection()返回的 HBITMAP作图是没有什么问题的。
首先,你可以不必把DIB转换成DDB就可以让它显示在设备上。但是那样的话程序运行会慢,而且也不能使用一些有关DDB操作的函数功能了,诸如BitBlt()…
以下是从DIB创建一个DDB的基本步骤:
- 从DIB颜色表信息中的信息可以创建一个逻辑调色板,如果设备支持的话,你只需要做这一步。为了创建一个调色板,就需要分配给逻辑调色板结构。初始化palversion和palnumentries,从DIB中的颜色表把颜色数拷贝过来。然后我们就可以使用createpalette()函数来使用我们初始化的逻辑调色板了。
- 把逻辑调色板选到设备中,然后实现它。
- 创建DDB,可以使用createdibbitmap()函数。 create dib bitmap
- 最后不要忘记释放掉分给逻辑调色板结构的内存。
虽然这样就可以创建一个逻辑调色板了,但它没有返回信息给所调用的程序代码。
如果DIB描述的是一个256色的位图的话,而且设备也只支持256色,那么DDB可能就不能正确的显示在设备上。那是因为系统使用的颜色数与位图的颜色数不相同,因此,你要修改一下,在我们画位图之前,就让它返回逻辑调色板,然后我们选择和实现它到设备的上下文。
//以下是程序代码
hbitmap dibtoddb(handle hdib ) // DIB to DDB
{
lpbitmapinfoheader lpbi;
hbitmap hbm;
cpalette pal;
cpalette* poldpal;
cclientdc dc(null);
if (hdib == null)
return null;
lpbi = (lpbitmapinfoheader)hdib; // 图像信息头
int ncolors = lpbi->biclrused ? lpbi->biclrused :
1 << lpbi->bibitcount;
bitmapinfo &bminfo = *(lpbitmapinfo)hdib ;
lpvoid lpdibbits;
if( bminfo.bmiheader.bibitcount > 8 )
lpdibbits = (lpvoid)((lpdword)(bminfo.bmicolors +
bminfo.bmiheader.biclrused) +
((bminfo.bmiheader.bicompression == bi_bitfields) ? 3 : 0));
else
lpdibbits = (lpvoid)(bminfo.bmicolors + ncolors);
// create and select a logical palette if needed
if( ncolors <= 256 && dc.getdevicecaps(rastercaps) & rc_palette) { uint nsize="sizeof(logpalette)" + (sizeof(paletteentry) * ncolors); logpalette *plp="(logpalette" *) new byte[nsize]; plp->palversion = 0x300;
plp->palnumentries = ncolors;
for( int i=0; i palpalentry[i].pered = bminfo.bmicolors[i].rgbred;
plp->palpalentry[i].pegreen = bminfo.bmicolors[i].rgbgreen;
plp->palpalentry[i].peblue = bminfo.bmicolors[i].rgbblue;
plp->palpalentry[i].peflags = 0;
}
pal.createpalette( plp );
delete[] plp;
// select and realize the palette
poldpal = dc.selectpalette( &pal, false );
dc.realizepalette();
}
hbm = createdibitmap(dc.getsafehdc(), // 设备上下文的句柄
(lpbitmapinfoheader)lpbi, // 位图信息头指针
( long )cbm_init, // 初始化标志
lpdibbits, // 初始化数据指针
(lpbitmapinfo)lpbi, // 位图信息指针
dib_rgb_colors ); // 颜色数据的使用方式
if (pal.getsafehandle())
dc.selectpalette(poldpal, false );
return hbm;
}
使用DIB 转 DDB 方法
HBITMAP CDIB::GetBitmap() const
{
assertdc();
HDC pDC = GetDC(NULL);
HDC hMemDC = CreateCompatibleDC(pDC);
HBITMAP hBitmap = CreateCompatibleBitmap(pDC,
m_bmiHeader.biWidth,
m_bmiHeader.biHeight);
HGDIOBJ hOldBmp = SelectObject(hMemDC, hBitmap);
StretchDIBits(hMemDC,
0, 0, m_bmiHeader.biWidth, m_bmiHeader.biHeight,
0, 0, m_bmiHeader.biWidth, m_bmiHeader.biHeight,
m_imgData, (LPBITMAPINFO)&m_bmiHeader, DIB_RGB_COLORS, SRCCOPY);
SelectObject(hMemDC, hOldBmp);
DeleteDC(hMemDC);
ReleaseDC(NULL, pDC);
return hBitmap;
}
函数介绍:
首先明确最主要区别: CreateDIBitmap创建的是 设备相关位图句柄 - HBITMAP.
CreateDIBSection创建的是 设备无关位图句柄 - HBITMAP.
CreateDIBitmap用法
函数功能:
该函数由与设备无关的位图(DIB)创建与设备有关的位图(DDB),并且有选择地为位图置位。
函数原型:
HBITMAP CreateDIBitmap(HDC hdc, CONST BITMAPINFONEADER *lpbmih,DWORD fdwlnit,CONST VOID *lpblnit,CONST BITMAPINFO *lpbmi,UINT fuUsage);
参数:
- hdc:设备环境句柄。
- lpbmih:指向位图信息头结构的指针,它可以是下列操作系统位图信息头之一:
Windows NT 3.51和早期:BITMAPINFOHEADER;Windows NT 4.0和Windows 95:BITMAPV4HEADER;
Windows NT 5.0和Windows 98:BITMAPV5HEADER。
如果fdwlnit是CBM_INIT,那么函数使用位图信息头结构来获取位图所需的宽度、高度以及其他信息。
注意高度若是正数,那么表示是自底向上DIB,而负数表示为自顶向下DIB,这种情况与CreateDIBitmap函数兼容。 - fdwlnit:位标识集。它指定系统如何对位图的位进行初始化。
下面是定义的位标志常量:
CBM_INIT:如果设置了该标志,那么系统将使用lpblnit和lpbmi两个参数指向的数据来对位图中的位进行初始化。如果没有该标志,那么表示上述两个参数指向的数据无效。如果fdwlnit为0,那么系统不会对位图的位进行初始化。 - lpblnit:该指针指向包含初始的位图数据的字节类型数组。数据格式与参数lpbmi指向的BITMAPINFO结构中的成员biBitCount有关。
- lpbmi:指向BITMAPINFO结构的旨针。该结构描述了参数lpbmi指向的数组的维数和颜色格式。
- fuUsage:表示BITMAPINFO结构的成员bmiColors是否初始化过,并且如果是,那么bmiColors是否包含明确的红、绿、蓝(RGB)值或调色板索引。参数fuUsage必须取下列值中的一个,这些值的含义为:
DIB_PAL_COLORS:表示提供一个颜色表,并且该表由该位图要选入的设备环境的逻辑调色板的16位索引值数组组成。
DIB_RGB_COLORS:表示提供一个颜色表,并且表中包含了原义的RGB值。
返回值:
如果函数执行成功,返回值则是创建的位图的句柄;如果函数执行失败,那么返回值为NULL,若想获取更多错误信息,请调用GetLastError函数。
备注:用于fdwlnit参数的CBM_CREATDIB标志不再被支持。当不再需要该位图时,可调用DeleteObject函数删除它。
ICM:参数fuUsage用来指定参数lpbmi指向的BITMAPINFO结构中的成员bmiColors是否包含颜色信息。如果bmiColors不包含颜色信息,那么不能进行位图的颜色管理。BITMAPINFO中的bmiColors成员必须包含BITMAPV4HEADER或BITMAPV5HEADER,以便能够进行颜色管理。在创建完位图之后,产生的位图的内容颜色不匹配。
速查:Windows NT:3.1及以上版本;Windows:95及以上版本;Windows CE:不支持;头文件:wingdi.h;库文件:gdi32.lib。
边栏推荐
猜你喜欢
随机推荐
【3D建模制作技巧分享】ZBrush如何重新拓扑
The upgrade and transformation plan of the fortress machine for medium and large commercial banks!Must see!
If you can't get your heart, use "distributed lock" to lock your people
SQL Server calls WebService
Rt-thread [二] 系统初始化流程
Jbpm3.2 开发HelloWorld (简单请假流程)客户端
今天又做了三个梦,其中一个梦梦里的我还有意识会思考?
阿里巴巴2022届秋招面试真题和答案!
深度学习 RNN架构解析
【3D建模制作技巧分享】在zbrush中如何雕刻头发 ZBrush头发雕刻小技巧
Both synchronized and ReentrantLock are smooth, because they are reentrant locks, and a thread will not deadlock if it takes the lock multiple times. We need reentrant locks
How to right use of WebSocket in project
关于el-table列表渲染
Rt-thread [三] link.lds链接脚本详解
QT 子窗口—>主窗口 信号和槽的交互
The Record of Reminding myself
Qt面试题整理
【游戏建模模型制作全流程】使用ZBrush制作骷髅王
LocalDateTime的详细使用方法
现在学习次世代3D游戏建模还能找到高薪好工作吗
![单片机原理[一] 学好单片机必会的五张图](/img/65/cac34bee5470ae85288d4366d8d957.jpg)






![MQTT[一]基础知识介绍](/img/25/3ba24127e2258902b2d5ecc7c3727b.png)

