如何在屏幕上显示像素向量?

问题描述 投票:0回答:1

我从桌面创建屏幕截图并接收带有像素数据的矢量,但在尝试在屏幕上绘制像素数据时遇到问题。

创建屏幕截图片段的代码

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);
}

问题是绘制的屏幕截图顶部是黑色的,这意味着有些东西不起作用。

This is what it looks like

我做错了什么?

c++ winapi bitblt
1个回答
0
投票

首先,我要道歉的是,我只在裸机项目中使用了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
足够大,可以容纳图像的一部分,但不能容纳整个图像。

© www.soinside.com 2019 - 2024. All rights reserved.