c++ 如何在屏幕上显示像素矢量?

2ledvvac  于 2023-08-09  发布在  其他
关注(0)|答案(1)|浏览(118)

我从桌面创建了一个屏幕截图,并收到了一个带有像素数据的矢量,但在试图在屏幕上绘制像素数据时遇到了问题。
创建屏幕快照的代码

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 = height;
    bmi.bmiHeader.biWidth = 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);
}


问题是,绘制的屏幕截图顶部是黑色的,这意味着有些东西不起作用。
This is what it looks like
我做错了什么?

kyxcudwk

kyxcudwk1#

首先,我必须道歉,我只在裸机项目中使用过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行”在做什么;可能vectorx 1 m3n1x的大小被改变,因此它具有至少21个元素。
不过,我可以肯定地告诉你在“第3行和第4行”中发生了什么:
在第3行中,生成指向vector的元素[0]的指针。
在第4行中,对指针(而不是对vector)执行操作。这意味着编译器不知道此操作会访问example2vector中的元素。
因此,编译器绝对不会重新调整此行中vector的大小。
如果vectorexample2已经大于300个元素,“第4行”将写入example2[300];如果它小于301个元素,这行代码将写入RAM中的任何位置,并且可能会因为覆盖重要数据(如堆栈上的返回地址)而导致程序崩溃。
因此,在访问pExample[300]之前,必须确保example2已经大于300个元素。
这跟你的问题有什么关系?
Windows API函数执行指针操作,而不是vector操作。
这意味着:GetDIBits()的内部工作方式如下:

... GetDIBits(..., RGBQUAD * pExample, ...)
{
    ...
    pExample[0] = ...;
    pExample[1] = ...;
    ...
    pExample[width * height - 1] = ...;
    ...
}


因此,在调用GetDIBits()之前,必须确保向量v_pixel_data的大小至少为width * height个元素。
问题是,绘制的截图顶部是黑色的,这意味着有什么东西不工作。
Windows首先存储底部像素,最后存储顶部像素。
也许,你的vector足够大,可以容纳图像的一部分,但不能容纳完整的图像。

相关问题