Снимок экрана - PullRequest
       4

Снимок экрана

0 голосов
/ 07 сентября 2011

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

До сих пор я придумал следующее решение:

    /**
    * Creates a screenshot of the entire screen
    * @param img - 2d array containing RGB values of screen pixels.
    */
    void get_screenshot(COLORREF** img, const Rectangle &bounds)
    {
        // get the screen DC
        HDC hdc_screen = GetDC(NULL);
        // memory DC so we don't have to constantly poll the screen DC
        HDC hdc_memory = CreateCompatibleDC(hdc_screen);
        // bitmap handle
        HBITMAP hbitmap = CreateCompatibleBitmap(hdc_screen, bounds.width, bounds.height);
        // select the bitmap handle
        SelectObject(hdc_memory, hbitmap);
        // paint onto the bitmap
        BitBlt(hdc_memory, bounds.x, bounds.y, bounds.width, bounds.height, hdc_screen, bounds.x, bounds.y, SRCPAINT);
        // release the screen DC
        ReleaseDC(NULL, hdc_screen);
        // get the pixel data from the bitmap handle and put it into a nice data structure
        for(size_t i = bounds.x; i < bounds.x + bounds.width; ++i)
        {
            for(size_t j = bounds.y; j < bounds.y + bounds.height; ++j)
            {
                img[j-bounds.y][i-bounds.x] = GetPixel(hdc_memory, i, j);
            }
        }
        // release our memory DC
        ReleaseDC(NULL, hdc_memory);
    }

* Примечание. Прямоугольник - это на самом деле структура, которую я создал с 4 size_t полями для верхней левой координаты x & y, а также шириной и высотой прямоугольника.Это не прямоугольник WinAPI.

У меня было несколько вопросов по поводу этого кода:

  1. Правильно ли я освобождаю все ресурсы?
  2. Есть ли лучший способсделай это?Я ищу что-то с аналогичным уровнем сложности и гибкости, который имел бы 2d массив значений RGB.Окончательная обработка данных снимка экрана будет выполнена с помощью OpenCL, поэтому я бы предпочел не иметь какой-либо сложной структуры.

Ответы [ 2 ]

1 голос
/ 07 сентября 2011
  1. Вы забыли DeleteObject(hbitmap).

  2. CreateDIBSection создает HBITMAP, биты данных которого доступны непосредственно через указатель памяти, поэтому, используя его, вы можете избежатьfor полностью зацикливается.

  3. Добавьте флаг CAPTUREBLT вместе с SRCCOPY, иначе многослойные (прозрачные) окна не будут включены.

  4. Выберите растровое изображение обратно из памяти DC после цикла.

  5. Вы должны вызвать DeleteDC, а не ReleaseDC в памяти DC.(Если он у вас есть, отпустите его. Если вы его создадите, удалите его.)

Если вы хотите более эффективный подход, вы можете использовать DIBSECTION вместо совместимого растрового изображения,Это позволит вам пропустить медленный цикл GetPixel и получить данные пикселей, записанные непосредственно в структуру данных в нужном формате.

0 голосов
/ 07 сентября 2011

Меня только что познакомили с чудесным миром CImage .

    /**
    * Creates a screenshot of the specified region and copies it to the specified region in img.
    */
    void get_screenshot(CImage &img, const CRect & src_bounds, const CRect &dest_bounds)
    {
        // get the screen DC
        HDC hdc_screen = GetDC(nullptr);
        // copy to a CImage
        CImageDC memory_dc(img);
        //StretchDIBits(
        StretchBlt(memory_dc, dest_bounds.left, dest_bounds.top, dest_bounds.Width(), dest_bounds.Height(), hdc_screen, src_bounds.left, src_bounds.top, src_bounds.Width(), src_bounds.Height(), SRCCOPY);
        ReleaseDC(nullptr, memory_dc);
        ReleaseDC(nullptr, hdc_screen);
    }

Затем, чтобы использовать, просто создайте CImage объект, и вызовите GetBits() и приведите его к чему-то вроде char* и вуаля. Мгновенный доступ к данным изображения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...