Захватить данные пикселей только из указанного окна - PullRequest
1 голос
/ 29 марта 2020

Я хочу код ниже , чтобы сделать снимок экрана только с указанным окном, потому что таким образом BitBlt работает быстрее. Приведенный ниже код делает снимок экрана с окном, заданным именем окна, загружает данные пикселей в буфер и затем повторно рисует aws картинку на экране, чтобы доказать, что копирование сработало.

Я бы хотел сделать скриншоты браузера windows, как Google Chrome, но он не работает . На моем экране нарисован aws черный прямоугольник с правильными размерами окна.

Кажется, что работает все время с окном Minecraft.

Также работал с браузером Tor.

Я заметил, что после запроса информации о окне в окне minecraft не было child- windows, но когда оно не работало с остальными, все у них было несколько детей - windows.

#include<iostream>
#include<Windows.h>
#include<vector>

using namespace std;

int main() {
    HWND wnd = FindWindow(NULL, "Minecraft 1.15.1");//Name of window to be screenshoted
    if (!wnd) {
        std::cout << "e1\n";
        std::cin.get();
        return 0;
    }
    WINDOWINFO wi = { 0 };
    wi.cbSize = sizeof(WINDOWINFO);

    GetWindowInfo(wnd, &wi);

    RECT rect;
    GetWindowRect(wnd, &rect);

    int width = wi.rcClient.right - wi.rcClient.left;
    int height = wi.rcClient.bottom - wi.rcClient.top;

    cout << width << height;
    /////Fetch window info^^^^^^^^



    BYTE* ScreenData = new BYTE[4 * width*height];


    // copy screen to bitmap
    HDC     hScreen = GetWindowDC(wnd);
    HDC     hDC = CreateCompatibleDC(hScreen);
    HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, width, height);
    HGDIOBJ old_obj = SelectObject(hDC, hBitmap);
    BitBlt(hDC, 0, 0, width, height, hScreen, 0, 0, SRCCOPY);
    SelectObject(hDC, old_obj);

    BITMAPINFO bmi = { 0 };
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    std::cout << GetDIBits(hDC, hBitmap, 0, 0, NULL, &bmi, DIB_RGB_COLORS)<<endl;
    //std::cout << bmi.bmiHeader.biHeight<< " "<< bmi.bmiHeader.biWidth<<endl;
    BYTE*buffer = new BYTE[4* bmi.bmiHeader.biHeight*bmi.bmiHeader.biWidth];
    bmi.bmiHeader.biHeight *= -1;
    std::cout<<GetDIBits(hDC, hBitmap, 0, bmi.bmiHeader.biHeight, buffer, &bmi, DIB_RGB_COLORS)<<endl;//DIB_PAL_COLORS
    /////Load window pixels into a buffer^^^^^^^^


    POINT p;
    int r = 0;
    int g = 0;
    int b = 0;
    int x = 0;
    int y = 0;
    HDC sc = GetDC(NULL);
    COLORREF color;

    while (true) {
        if ((y*-1) == bmi.bmiHeader.biHeight+1 && x == bmi.bmiHeader.biWidth-1) { break; }
        r = (int)buffer[4 * ((y*bmi.bmiHeader.biWidth) + x)+2];
        g = (int)buffer[4 * ((y*bmi.bmiHeader.biWidth) + x)+1];
        b = (int)buffer[4 * ((y*bmi.bmiHeader.biWidth) + x) ];
        color = RGB(r, g, b);
        SetPixel(sc, x, y, color);

        x++;
        if (x == bmi.bmiHeader.biWidth) {
            y++;
            x = 0;
        }
    }
    /////Prove that the copying was successful and buffer is full^^^^^^^^
    Sleep(5000);
    std::cout << "fin\n";
    std::cin.get();
    return 0;
}

1 Ответ

1 голос
/ 29 марта 2020

Мне кажется, проблема в том, что вы делаете что-то.

Прежде чем поместить растровое изображение в буфер обмена, вы должны выбрать его из контекста устройства памяти.

После того, как вы поместите растровые изображения в буфер обмена, у вас больше нет его, поэтому вам не следует пытаться удалить его.

Лучший способ сделать это, вероятно, - переместить ваш раздел // clean up перед разделом // save bitmap to clipboard и исключить ваше заявление DelectObject(hBitmap). Таким образом, конечный конец вашего кода, вероятно, должен быть:

BitBlt(hDC, 0, 0, width, height, hScreen, 0, 0, SRCCOPY);

// clean up
SelectObject(hDC, old_obj); // selects hBitmap out of hDC
DeleteDC(hDC);
ReleaseDC(NULL, hScreen);

// save bitmap to clipboard
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(CF_BITMAP, hBitmap);  // clipboard now owns the bitmap
CloseClipboard();

Если после этих изменений у вас все еще остается проблема, я бы проверил возвращаемое значение вызова SetClipboardData. Если это не удается, GetLastError может дать подсказку.

...