我正在尝试创建一个与Windows API GetPixel()函数等效的函数,但我想创建一个屏幕的位图,然后读取该缓冲区。
这就是我所拥有的(主要是从谷歌搜索中粘贴的副本),当我运行它时它只打印出0。我想我的大部分都是正确的,我的问题是我不知道如何阅读BYTE变量。
所以我的问题是,我需要做些什么来让它用我的for循环打印出一些随机颜色(R,G或B)?
#include <Windows.h>
#include <iostream>
#include <math.h>
#include <stdio.h>
using namespace std;
int main() {
HDC hdc,hdcMem;
hdc = GetDC(NULL);
hdcMem = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, 1680, 1050);
BITMAPINFO MyBMInfo = {0};
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
// Get the BITMAPINFO structure from the bitmap
if(0 == GetDIBits(hdcMem, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS)) {
cout << "error" << endl;
}
// create the bitmap buffer
BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage];
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
MyBMInfo.bmiHeader.biBitCount = 32;
MyBMInfo.bmiHeader.biCompression = BI_RGB;
MyBMInfo.bmiHeader.biHeight = abs(MyBMInfo.bmiHeader.biHeight);
// get the actual bitmap buffer
if(0 == GetDIBits(hdc, hBitmap, 0, MyBMInfo.bmiHeader.biHeight, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS)) {
cout << "error2" << endl;
}
for(int i = 0; i < 100; i++) {
cout << (int)lpPixels[i] << endl;
}
return 0;
}
答案 0 :(得分:3)
基本上,您需要绘制一些像素才能获得0以外的结果。
目前,main中的第4行代码会创建一个空(空白,0初始化)图像。然后,在第一次调用GetDIBits
时,您会获得有关此图片大小的信息。然后在第二次调用GetDIBits
时获得实际(空白)像素。
要解决此问题,只需将磁盘中的位图文件加载到hBitmap
并将此位图选择到hdcMem
。
即,改变
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, 1680, 1050);
这样的事情。
HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, "xpButton.bmp", IMAGE_BITMAP, 0,0, LR_LOADFROMFILE);
HBITMAP old = (HBITMAP) SelectObject(hdcMem, hBitmap);
(确保使用有效的bmp文件名。我的文件名与.cpp文件位于同一文件夹中,因为当您通过IDE运行时,这是当前的目录。如果您希望通过资源管理器运行,将另一个bmp副本放在与exe文件相同的文件夹中
这是我使用的bmp(上传到SO后已转换为png):
这是循环中的前10次迭代。
255
5
253
0
255
5
253
0
255
5
请注意,0,0处的像素的颜色为:rgb(253,5,255),它是8位图像,因此没有alpha通道,因此它的值为0。像素存储为[BGRA],[BGRA],[BGRA]等。 我将留给您修复程序的(不存在的)清理部分。 Windows将取消分配您在此处使用的内存,但绝对不应该养成不释放您已分配的内存的习惯。 :)
答案 1 :(得分:3)
按照约定,我在工作代码片段中添加了一个新答案(我添加了缺少的lpPixels清理)。请参阅我之前的答案和@enhzflep撰写的讨论。
#include <Windows.h>
#include <iostream>
#include <math.h>
#include <stdio.h>
using namespace std;
HBITMAP GetScreenBmp( HDC hdc) {
// Get screen dimensions
int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
// Create compatible DC, create a compatible bitmap and copy the screen using BitBlt()
HDC hCaptureDC = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, nScreenWidth, nScreenHeight);
HGDIOBJ hOld = SelectObject(hCaptureDC, hBitmap);
BOOL bOK = BitBlt(hCaptureDC,0,0,nScreenWidth, nScreenHeight, hdc,0,0,SRCCOPY|CAPTUREBLT);
SelectObject(hCaptureDC, hOld); // always select the previously selected object once done
DeleteDC(hCaptureDC);
return hBitmap;
}
int main() {
HDC hdc = GetDC(0);
HBITMAP hBitmap = GetScreenBmp(hdc);
BITMAPINFO MyBMInfo = {0};
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
// Get the BITMAPINFO structure from the bitmap
if(0 == GetDIBits(hdc, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS)) {
cout << "error" << endl;
}
// create the bitmap buffer
BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage];
// Better do this here - the original bitmap might have BI_BITFILEDS, which makes it
// necessary to read the color table - you might not want this.
MyBMInfo.bmiHeader.biCompression = BI_RGB;
// get the actual bitmap buffer
if(0 == GetDIBits(hdc, hBitmap, 0, MyBMInfo.bmiHeader.biHeight, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS)) {
cout << "error2" << endl;
}
for(int i = 0; i < 100; i++) {
cout << (int)lpPixels[i];
}
DeleteObject(hBitmap);
ReleaseDC(NULL, hdc);
delete[] lpPixels;
return 0;
}
答案 2 :(得分:1)
您的代码似乎有点混乱。我猜的片段太多了:)。 不过,你还是非常接近: 第一个GetDIBits()调用是为了获取填充的位图属性,正如代码中的注释所示。 你正在使用一个不必要的MemDC - 这可能来自一个想要在屏幕上做BitBlt的片段。
然后,您可以使用填充结构来获取第二个GetDIBits()调用的实际位图像素,但您正在做的是再次使用硬编码值替换属性,从而进行第一次GetDIBits()调用无用的。
所以:删除MemDC - 你不需要它 - 在第一次调用GetDIBits()时用hdc替换hdcMem,然后删除在第一次GetDIBits调用后覆盖bmiHeader成员的所有语句,你应该得到你的像素。
哦,当然不要忘记在dc和位图上调用ReleaseDC()/ DeleteObject()并删除[]缓冲区:)