GetDIBits and loop through pixels using X, Y

c++, getdibits, loops, pixel

Solution

Apart from the good answers already given, here's an example of how to get a simple array structure to walk on. (You can use e.g. Goz' code for the iteration.)

GetDIBits reference @ MSDN

You have to select `DIB_RGB_COLORS` as flag for `uUsage` and set up the `BITMAPINFO` structure and the `BITMAPINFOHEADER` structure it contains. When you set `biClrUsed` and `biClrImportant` to zero, there is "no" color table, so you can read the pixels of the bitmap you get from `GetDIBits` as a sequence of RGB values. Using `32` as bit count (`biBitCount`) sets up the data structure according to MSDN:

The bitmap has a maximum of 2^32 colors. If the `biCompression` member of the `BITMAPINFOHEADER` is `BI_RGB`, the `bmiColors` member of `BITMAPINFO` is `NULL`. Each `DWORD` in the bitmap array represents the relative intensities of blue, green, and red, respectively, for a pixel. The high byte in each `DWORD` is not used.

Since a MS `LONG` is exactly 32 bit long (the size of a `DWORD`), you do not have to pay attention to padding (as described in the Remarks section).

Code:

HDC hdcSource = NULL; // the source device context
HBITMAP hSource = NULL; // the bitmap selected into the device context

BITMAPINFO MyBMInfo = {0};
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);

// Get the BITMAPINFO structure from the bitmap
if(0 == GetDIBits(hdcSource, hSource, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS))
{
    // error handling
}

// create the pixel buffer
BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage];

// We'll change the received BITMAPINFOHEADER to request the data in a
// 32 bit RGB format (and not upside-down) so that we can iterate over
// the pixels easily. 

// requesting a 32 bit image means that no stride/padding will be necessary,
// although it always contains an (possibly unused) alpha channel
MyBMInfo.bmiHeader.biBitCount = 32;
MyBMInfo.bmiHeader.biCompression = BI_RGB;  // no compression -> easier to use
// correct the bottom-up ordering of lines (abs is in cstdblib and stdlib.h)
MyBMInfo.bmiHeader.biHeight = abs(MyBMInfo.bmiHeader.biHeight);

// Call GetDIBits a second time, this time to (format and) store the actual
// bitmap data (the "pixels") in the buffer lpPixels
if(0 == GetDIBits(hdcSource, hSource, 0, MyBMInfo.bmiHeader.biHeight,
                  lpPixels, &MyBMInfo, DIB_RGB_COLORS))
{
    // error handling
}
// clean up: deselect bitmap from device context, close handles, delete buffer

Problem

I'm grabbing a portion of the screen and scanning through the pixels for a certain color range. I looked at MSDN's Capturing an Image example and know how to use the functions. I can get the bits into an array, but I'm not sure how to do it in such a way that I can loop through it as I would an image. A pseudo-example (which I'm sure is way off): ``` for ( x = 1; x <= Image.Width; x += 3 ) { for ( y = 1; y <= Image.Height; y += 3 ) { red = lpPixels[x]; green = lpPixels[x + 1]; blue = lpPixels[x + 2]; } } ``` That's basically what I want to do, so if red, blue, and green is a certain color, I'll know what coordinate it's at (x, y) in the image. I just don't know how to use GetDIBits in such a way, and how to setup the array appropriately to be able to accomplish this.

Original source