I’m trying to have my program take a screenshot and then format the data in such a way that it can be easily manipulated from my program.
So far I’ve come up with the following solution:
/**
* 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);
}
*Note: Rectangle is actually a struct I created with 4 size_t fields for the top-left x & y coordinate, and the width and height of the rectangle. It is not the WinAPI Rectangle.
I had a few questions about this code:
- Am I properly releasing all resources?
- Is there a better way to do this? I’m looking for something with a similar level of complexity and flexibility a 2d array of RGB values would have. The final screen capture data processing will be done with OpenCL so I would prefer to not have any complicated structure.
You forgot to
DeleteObject(hbitmap).CreateDIBSectioncreates a HBITMAP which data bits are accessible directly through memory pointer, so using it you can avoid theforloops completely.Add
CAPTUREBLTflag along withSRCCOPY, otherwise layered (transparent) windows will not be included.Select the bitmap back out of the memory DC after the loop.
You should call
DeleteDCnotReleaseDCon the memory DC. (If you get it, release it. If you create it, delete it.)If you want a more efficient approach, you can use a
DIBSECTIONinstead of a compatible bitmap. This would let you skip the slowGetPixelloop and get the pixel data written directly into your data structure with the format you want.