我从桌面创建屏幕截图并接收带有像素数据的矢量,但在尝试在屏幕上绘制像素数据时遇到问题。
创建屏幕截图片段的代码
std::vector<RGBQUAD> recvScreenSnippet(int x, int y, int width, int height) {
std::vector<RGBQUAD> v_screen_data(width*height);
HDC screen_dc = GetDC(NULL);
HDC mem_dc = CreateCompatibleDC(NULL);
HBITMAP hBmp = CreateCompatibleBitmap(screen_dc, width, height);
auto oldBmp = SelectObject(mem_dc, hBmp);
// 32 bit & Upside Down headers
BITMAPINFO bmi{};
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biHeight = BITMAP_HEIGHT;
bmi.bmiHeader.biWidth = BITMAP_WIDTH;
bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
// Receive pixel data from hdc
BitBlt(mem_dc, 0, 0, width, height, screen_dc, x, y, SRCCOPY);
GetDIBits(mem_dc, hBmp, 0, height, &v_screen_data[0], &bmi, DIB_RGB_COLORS);
// Cleanup
SelectObject(mem_dc, oldBmp);
DeleteObject(hBmp);
DeleteDC(mem_dc);
ReleaseDC(0, screen_dc);
return v_screen_data;
}
在屏幕上绘制像素数据的代码:
void setScreenSnippet(int x, int y, int width, int height, std::vector<RGBQUAD> &v_pixel_data) {
HDC screen_dc = GetDC(0);
HDC mem_dc = CreateCompatibleDC(0);
// 32 bit & Upside Down headers
BITMAPINFO bmi{};
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biHeight = height;
bmi.bmiHeader.biWidth = width;
bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
// Create bitmap
HBITMAP bitmap = CreateCompatibleBitmap(mem_dc,width,height);
// Store pixel data in bitmap
SetDIBits(mem_dc, bitmap, 0, height, &v_pixel_data[0], &bmi, DIB_RGB_COLORS);
// Select bitmap data into mem_dc
SelectObject(mem_dc, bitmap);
while (true)
{
BitBlt(screen_dc, x, y, width, height, mem_dc, 0, 0, SRCCOPY);
Sleep(1);
}
// Cleanup
SelectObject(mem_dc, bitmap);
DeleteObject(bitmap);
ReleaseDC(0, screen_dc);
}
我怎么称呼它
int main()
{
Sleep(5000);
std::vector<RGBQUAD> v_pixel_data = recvScreenSnippet(600,600,400,400);
setScreenSnippet(100, 600, 400, 400, v_pixel_data);
system("pause"), exit(1);
}
问题是绘制的屏幕截图顶部是黑色的,这意味着有些东西不起作用。
我做错了什么?
首先,我要道歉的是,我只在裸机项目中使用了C++,没有使用标准库函数(
std::...
),所以我对这些函数的了解非常有限。
但是,让我们看看下面的代码:
std::vector<int> example1, example2;
example1[20] = 1; /* Line 2 */
int * pExample = &example2[0]; /* Line 3 */
pExample[300] = 2; /* Line 4 */
对
std::vector
数据类型了解不多,我无法告诉你“第 2 行”在做什么;也许 vector
example1
的大小已更改,因此它至少有 21 个元素。
但是,我可以肯定地告诉你“第 3 行和第 4 行”中发生了什么:
在第 3 行,生成了指向
[0]
的元素 vector
的指针。
在第 4 行中,执行了对指针(但不是对
vector
)的操作。这意味着编译器不知道此操作访问 example2
vector
中的元素。
因此,编译器绝对不会重新调整这一行中
vector
的大小。
如果
vector
example2
已经大于 300 个元素,“第 4 行”将写入 example2[300]
;如果它小于 301 个元素,这行代码将写入 RAM 中的任何位置,并且可能会崩溃你的程序会因为覆盖重要数据(例如堆栈上的返回地址)而崩溃。
因此,在访问
example2
之前,必须确保pExample[300]
已经大于300个元素。
这与您的问题有什么关系?
Windows API 函数执行指针操作,而不是
vector
操作。
这意味着:
GetDIBits()
内部工作原理如下:
... GetDIBits(..., RGBQUAD * pExample, ...)
{
...
pExample[0] = ...;
pExample[1] = ...;
...
pExample[width * height - 1] = ...;
...
}
因此,在调用
v_pixel_data
之前,必须确保向量 width * height
的大小至少为 GetDIBits()
个元素。
问题是绘制的屏幕截图顶部是黑色的,这意味着有些东西不起作用。
Windows 首先存储底部像素,最后存储顶部像素。
也许,您的
vector
足够大,可以容纳图像的一部分,但不能容纳整个图像。