问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

C++函数GetDIBits怎么用???????

发布网友 发布时间:2022-04-20 07:36

我来回答

1个回答

热心网友 时间:2023-11-17 01:51

HBITMAP是常用的GDI对象,而GetDIBits可以从一个HBITMAP对象中获得其对应的位数据。
其原型如下:
int GetDIBits( HDC hdc, // handle to DC
hdc, // handle to DC
HBITMAP hbmp, // handle to bitmap
UINT hbmp, // handle to bitmap
UINT uStartScan, // first scan line to set
UINT cScanLines, // number of scan lines to copy
LPVOID cScanLines, // number of scan lines to copy
LPVOID lpvBits, // array for bitmap bits
LPBITMAPINFO lpbi, // bitmap data buffer
UINT lpbi, // bitmap data buffer
UINT uUsage // RGB or palette index );
标准的GetDIBits调用方式是两次调用:
第一次传入空的 lpvBits,此时的lpbi作为传出参数,从中可以获得lpvBits所需的内存区域大小。
BYTE *lpvBits = NULL;
BITMAPINFO bmpInfo = {0};
bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader);
/* 第一次调用GetDIBits获得bmpInfo */
nRet = ::GetDIBits(hDC, hBitmap, 0, pBmpData->bmHeight, NULL, &bmpInfo, DIB_RGB_COLORS);
if (nRet == 0) {
nRet = GetLastError();
TRACE( _T("GetDIBits for bmpInfo failed %d/n"), nRet);
goto err;
}
以上调用如果成功,就会在bmpInfo.bmiHeader.biSizeImage记录位数据所占的内存区大小,
此时就可以动态分配内存,然后再次调用GetDIBits获得实际的位数据:
lpvBits= new BYTE[bmpInfo.bmiHeader.biSizeImage];
if (NULL == pBitsBuffer) {
nRet = -1;
TRACE( _T("Allocate memory for lpvBits failed/n"));
goto err;
}
/* 第二次调用GetDIBits获得位图数据 */
nRet = ::GetDIBits(hDC, hBitmap, 0, pBmpData->bmHeight, lpvBits, &bmpInfo, DIB_RGB_COLORS);
if (nRet == 0) {
nRet = GetLastError();
TRACE( _T("GetDIBits for lpvBits failed %d/n"), nRet);
goto err;
}
很多时候,因为位图的长宽和颜色深度都是已知的,因此位数据所占的内存区大小可以由公式
width * heigth * pixelBits / 8 计算获得
那是否可以省略第一步调用呢?
答案是:最好不要
原因是 bmpInfo.bmiHeader.biSizeImage 并不一定等于 width * heigth * pixelBits / 8
经过多次测试发现,对于16位颜色深度的位图,如果其宽度为奇数,则第一次GetDIBits获得
的位数据大小为 (width+1) * heigth * pixelBits / 8
也就是说对于16位颜色深度的位图,HBITMAP对象对其进行存储时,自动将宽度调整为了偶
数,也即将每行数据对齐到4字节(一个DWORD的长度)。
暂时没有查到相关的解释,我的猜想是这是为了在进行像素操作时能直接以DWORD为单位,
这样比以WORD为单位能减少一半的操作次数。

////
16位操作系统下如果使用这种方法获得的将是16位图
biBitCount=16

表示位图最多有2^16种颜色。每个像素用16位(2个字节)表示。这种格式叫作高彩色,或叫增强型16位色,或64K色。它的情况比较复杂,当biCompression成员的值是BI_RGB时,它没有调色板。16位中,最低的5位表示蓝色分量,中间的5位表示绿色分量,高的5位表示红色分量,一共占用了15位,最高的一位保留,设为0。//->备注1
这种格式也被称作555 16位位图。
内存分布如下

如果biCompression成员的值是BI_BITFIELDS,(const DWORD BI_BITFIELDS = 3;)那么情况就复杂了,首先是原来调色板的位置被三个DWORD变量占据,称为红、绿、蓝掩码。分别用于描述红、绿、蓝分量在16位中所占的位置。在Windows 95(或98)中,系统可接受两种格式的位域:555和565,在555格式下,红、绿、蓝的掩码分别是:0x7C00、0x03E0、0x001F,而在565格式下,它们则分别为:0xF800、0x07E0、0x001F。你在读取一个像素之后,可以分别用掩码“与”上像素值,

从而提取出想要的颜色分量(当然还要再经过适当的左右移操作)。在NT系统中,则没有格式*,只不过要求掩码之间不能有重叠。(注:这种格式的图像使用起来是比较麻烦的,不过因为它的显示效果接近于真彩,而图像数据又比真彩图像小的多,所以,它更多的被用于游戏软件)。我们只需要读取其中的R或者G的掩码,来判断是那种格式。以红色掩码为例 0111110000000000的时候就是555格式 1111100000000000就是565格式。
555 格式 xrrrrrgggggbbbbb
565 格式 rrrrrggggggbbbbb
解析555格式的代码:
BYTE b= bmpData[i*storeWidth+j];
BYTE g=((bmpData[i*storeWidth+j +1]<<6)>>3)+(buffer[i*storeWidth+j]>>5);
BYTE r=(bmpData[i*storeWidth+j +1]<<1)>>3;
有一点值得提醒的是由于有较多的位操作,所以在处理的时候在前一次操作的上面加上一对括号。
现在我们得到了55RGB各自的分量,但是还有一个新的问题,那就是由于两字节表示了3个颜色 555下每个颜色最多到0x1F。所以我们需要一个转换,这就是掩码的用武之地,将得到的各颜色分量和相应的掩码做与运算,或者乘8就可以了,推荐用与运算。

以下是565格式时的数据分离:
BYTE b= bmpData[i*storeWidth+j];
BYTE g=((bmpData[i*storeWidth+j+1]<<5)>>2)+(buffer[i*storeWidth+j]>>5);
BYTE r=bmpData[i*storeWidth+j +1]>>3;

现在我们得到了565RGB各自的分量,但是仍然还有一个新的问题,565格式下最大的绿色分量也就0x3F。所以我们需要一个转换,这就是掩码的用武之地,将各颜色分量和相应的掩码做与运算,

备注一:
所以这种方法需要通过位移来操作 在写抓屏程序的时候显示不如后边的32位图来的方便, 但是在颜色质量为16位的操作系统下如何抓屏到32位的图像呢
通过上边的两个GetDIBits的方法是不可行的 第一次LPVOID lpvBits, 为空 获得了BITMAPINFO bi信息bi.bmiHeader.biBitCount = 16;
如果想通过修改bi.bmiHeader.biBitCount = 32; 后来第二次调用GetDIBits就会失败 ;

那如何在颜色质量为16位的操作系统下如何获得32位的图像呢?
方法如下:
首先使用 GetObject(HBITMAP bmpScreen) 获得信息
然后通过修改BITMAPINFO 中的biBitCount 为32就可以获得32位结构的LPVOID 了 再进行操作就方便的多了

[cpp] view plaincopy
BITMAPINFO bi = {0};
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);

bi.bmiHeader.biWidth = bmpScreen.bmWidth;
bi.bmiHeader.biHeight = bmpScreen.bmHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 16;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biSizeImage = 0;
bi.bmiHeader.biXPelsPerMeter = 0;
bi.bmiHeader.biYPelsPerMeter = 0;
bi.bmiHeader.biClrUsed = 0;
bi.bmiHeader.biClrImportant = 0;

biBitCount=32

表示位图最多有2^32种颜色。这种位图的结构与16位位图结构非常类似,当biCompression成员的值是BI_RGB时,它也没有调色板,32位中有24位用于存放RGB值,顺序是:最前一字节保留,红8位、绿8位、蓝8位。这种格式也被成为888 32位图。如果biCompression成员的值是BI_BITFIELDS时,原来调色板的位置将被三个DWORD变量占据,成为红、绿、蓝掩码,分别用于描述红、绿、蓝分量在32位中所占的位置。在Windows 95(or98)中,系统只接受888格式,也就是说三个掩码的值将只能是:0xFF0000、0xFF00、0xFF。而在NT系统中,你只要注意使掩码之间不产生重叠就行。
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
临沂比较有名的男装品牌 呼伦贝尔市悦动网络科技有限公司怎么样? 呼伦贝尔中汇实业有限公司怎么样? 呼伦贝尔油玉不绝电子商务有限公司怎么样? 如何避免wps卡顿? 属鼠的男人找对象是属什么,属鼠的人和什么属相合 96年鼠的姻缘在哪年 属相相合年份运势提升 2024属鼠找对象属什么最佳 黑客攻击网站能报案吗 黑客攻击报案有用吗 关于电脑方面的一些专有英语词汇都有哪些? 求助流式staining buffer 的配方 javamail接收邮件怎么解析内容 请给出电路、电子系统中,缓冲器的比较权威点的定... 如何用python读取文件数据,并插入到influxdb数据库 如何从持久化存储中读取数据 翻译英文科室牌 python 读取本地数据然后插入到另一个数据库中 汇编加法进位如何放到内存 雅思作文如何提高 C语言定时器求助 高分求翻译。急!谢谢 如何检查黑苹果显卡正常驱动 PrimeScript Buffer是什么意思 oracle store in 属性存储在哪儿 电脑缺少硬盘驱动,无法安装系统问题 store和shop有什么区别? store buffer为什么能避免 war and waw store buffer load buffer在哪 有哪些格调满满,好用不贵的大学生数码产品? android做IM 有没有合适的socket框架 socket高并发网络编程服务端有什么框架? 4.socket框架netty的使用,以及nio的实现原理,为... java socket编程 服务器和客户端程序都连接不上,急... php socket 框架有哪些 SOCKET客户端框架有哪些? socket/tcpip框架 怎么理解 socket 模式是一个怎样的意思,它有包括很多模式吗... c#下面有什么好的Socket 框架 有没有好的python socket框架推荐 java套接字测试程序出现空指针错误:java.lang.Nul... android上的socket通信的开源框架有哪些 C/C++ 有哪些适合快速开发的socket服务器框架 一个JFrame和Socket的问题: 有没有哪些高效的c++ socket框架 ios用什么框架做socket开发 python有类似node下面socket.io的socket框架么 北蜂窝路15号怎么样?好不好?值不值得买? 北京北站离海淀区北蜂窝路甲15号远吗。 广安门 交通银行在哪?