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开发者_C百科 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)
.CreateDIBSection
creates a HBITMAP which data bits are accessible directly through memory pointer, so using it you can avoid thefor
loops completely.Add
CAPTUREBLT
flag 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
DeleteDC
notReleaseDC
on 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 DIBSECTION
instead of a compatible bitmap. This would let you skip the slow GetPixel
loop and get the pixel data written directly into your data structure with the format you want.
I was just introduced to the wonderful world of 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);
}
Then to use, just create a CImage
object, and call GetBits()
and cast it to something like char*
and voila. Instant access to the image data.
精彩评论