I had a function I used a while back to test the pixel colors in a given screen rect, it was something like this pseudo code.

for (int y = t; y <= b; y++){

        for (int x = l; x <= r; x++){

            color = GetPixel(hdc_, x, y) & 0x00FFFFFF;
            if (color == col){

                //cout << "+ " << x << " x " << y << " = " << color << endl << flush;
                *rx = x;
                *ry = y;
                return 1;

            }


        }

I am wanting to update this code to something, well... better, and faster.
But I don't know how to iterate through the array which contains the data I want, in the same manner I prefer, which is (keeping a rectangle in mind) top left to top right, top to bottom.

Here is my latest code...

void GetPixels(int x, int y, int w, int h)
{
    HDC hdc = GetDC(NULL);
    RECT rect = { x, y, x + w, y + h };
    HDC rectDC = CreateCompatibleDC(hdc);
    HBITMAP hbmp = CreateCompatibleBitmap(rectDC, w, h);

    DeleteObject(SelectObject(rectDC, hbmp));

    BitBlt(rectDC, 0, 0, w, h, hdc, x, y, SRCCOPY);

    BITMAPINFO BMI;
    BMI.bmiHeader.biSize = sizeof(BMI.bmiHeader);
    BMI.bmiHeader.biWidth = w;
    BMI.bmiHeader.biHeight = h;
    BMI.bmiHeader.biPlanes = 1;
    BMI.bmiHeader.biBitCount = 32;
    BMI.bmiHeader.biCompression = BI_RGB;

    RGBQUAD *pPixels = new RGBQUAD[w * h];

    GetDIBits(
        rectDC,
        hbmp,
        y,
        h,
        pPixels,
        &BMI,
        DIB_RGB_COLORS
        );

    // here I need to somehow loop through the array of RGBQUAD struct in a rect manner.
    //std::cout << pPixels[0] << std::endl;

    delete[] pPixels;
}

Thanks for considering my question, I appreciate your time.

Something like:

for (int h = 0; h < height; h++)
{
    for (int w = 0; w < width; w++)
    {
        // do whatever
        // pPixels[w + h*width];
    }
}

Thanks nullptr, that got me on track.

I have a related issue, still regarding pixels.

In my old function GetPixel() function returns a different value than what I get from this and similar methods of doing it.
For example GetPixel (when output as hex) will be 00FF00 for a green pixel and say ADEFCA for some random colour, but getting the pixels into buffer like above the same pixels will output FF00FF00 for green and FFADEFCA for the random. So i have an extra (is it high byte?) and I'm not sure how to deal with that.

Edited 1 Year Ago by Suzie999

typedef struct tagRGBQUAD {
  BYTE rgbBlue;
  BYTE rgbGreen;
  BYTE rgbRed;
  BYTE rgbReserved; // must be zero
} RGBQUAD;

Just mask out the most significant byte.
pPixels[idx] & 0xFFFFFF

Thanks again nullptr, still not getting the correct values.
I realized the test diirection should really be (visualizing it as a grid of 10 x 10 pixels) From top to botton (row 0 column 0 to row 9 column 0) then (row 0 column 1 to row 9 column 1) etc..
Here is latest function, with some visual debugging.

void PixelsGet(int x, int y, int w, int h)
{
    HDC hdcSource = GetDC(NULL);
    //RECT rect = { x, y, x + w, y + h };

    HDC hdcDest = CreateCompatibleDC(hdcSource);
    std::cout << "CreateCompatibleDC " << hdcDest  << std::endl; // looks good

    HBITMAP hbmp = CreateCompatibleBitmap(hdcDest, w, h);
    std::cout << "CreateCompatibleBitmap " << hbmp << std::endl; // looks good

    HGDIOBJ currentObj = SelectObject(hdcDest, hbmp);
    std::cout << "SelectObject " << currentObj << std::endl; // looks good

    BOOL BB = BitBlt(hdcDest, 0, 0, w, h, hdcSource, x, y, SRCCOPY);
    std::cout << "BitBlt " << BB << std::endl; // looks good

    BITMAPINFO BMI;
    BMI.bmiHeader.biSize = sizeof(BMI.bmiHeader);
    BMI.bmiHeader.biWidth = w;
    BMI.bmiHeader.biHeight = h;
    BMI.bmiHeader.biPlanes = 1;
    BMI.bmiHeader.biBitCount = 32;
    BMI.bmiHeader.biCompression = BI_RGB;

    RGBQUAD *pPixels = new RGBQUAD[w * h];

    int GDB = GetDIBits(hdcDest, hbmp, y, 0 - h, pPixels, &BMI, DIB_RGB_COLORS);
    std::cout << "GetDIBits " << GDB << std::endl; // looks good

    for (int column = 0; column < w; column++)
    {
        for (int row = 0; row < h; row++)
        {
            std::cout << std::hex << (DWORD)GetPixel(hdcSource, column, row) << "-"; // one color (the correct color)

            std::cout << std::hex << (DWORD)pPixels[(column * w) + row].rgbRed << 
                (DWORD)pPixels[(column * w) + row].rgbGreen <<
                (DWORD)pPixels[(column * w) + row].rgbBlue << " "; // different color
        }
        std::cout << std::endl;
    }

    BOOL delObj = DeleteObject(currentObj);
    std::cout << "DeleteObject " << delObj << std::endl;
    delete[] pPixels;
}

Thanks for looking.

Edited 1 Year Ago by Suzie999

The only major thing that stands out is the call to GetDIBits.
Try

int GDB = GetDIBits(hdcDest, hbmp, 0, BMI.bmiHeader.biHeight, pPixels, &BMI, DIB_RGB_COLORS);

Thanks for suggestion I tried but still not getting the results I expect :(
As far as I can see BMI.bmiHeader.biHeight == h and I only put 0 - 7 as height because of this line in remarks on msdn page

A bottom-up DIB is specified by setting the height to a positive number, while a top-down DIB is specified by setting the height to a negative number. The bitmap color table will be appended to the BITMAPINFO structure.

Change the iteration to

for (int row = 0; row < h; row++)
{
    for (int column = 0; column < w; column++)
    {
        std::cout << std::hex << (DWORD)GetPixel(hdcSource, column, row) << "-"; 
        std::cout << std::hex << (DWORD)pPixels[(row * w) + column].rgbRed << 
            (DWORD)pPixels[(column * w) + row].rgbGreen <<
            (DWORD)pPixels[(column * w) + row].rgbBlue << " ";
    }
    std::cout << std::endl;

That way you should be comparing the same pixel in GetPixel and pPixels.

Edited 1 Year Ago by nullptr

This the output...

CreateCompatibleDC E1012157
CreateCompatibleBitmap C50520CC
SelectObject 0185000F
BitBlt 1
343434-a2bcd8 343434-a2bad6 343434-61b9d4 343434-6fb7d3 343434-6fb6d2 343434-91b5d1 343434-75b4d1 34
3434-f2b4d0 343434-99b4d0 343434-273434
d0b498-9fbcd8 d0b498-9fbad6 d0b498-5cb9d4 d0b498-70b7d3 d0b498-65b6d2 d0b498-93b5d1 d0b498-55b4d1 d0
b498-b5b4d0 d0b498-e9b4d0 d0b498-763434
d0b498-9e6c77 d0b498-9e6c7a d0b498-637284 d0b498-6198af d0b498-7fb6d2 d0b498-64b5d1 ac947e-a9b4d1 85
7060-44b4d0 755f51-ddb4d0 765e4f-e63434
d1b499-9b7982 d1b499-9b7d8c d1b499-826f81 d1b499-515e70 caae94-7b6b7c 796759-71aec9 746358-85b4d1 7e
6f67-7bb4d0 7e7169-6db4d0 7f7168-df3434
d1b599-9a7e96 d1b599-9a718f d1b599-9a8699 c9ae93-5b7f89 6e5e51-687180 7d6f66-785e6e 7d7370-6baeca 83
7775-91b4d0 928582-61b4d0 7d6e69-8e3434
d2b69a-999aad d2b69a-9999ad d2b69a-996c83 7c6b5b-937789 807168-517b85 857b78-666f7d 806f6b-706779 9f
9391-75b4d0 726461-82b4d0 9b8f8e-693434
d3b79b-997a81 d3b79b-995c73 af9882-99acb9 705e51-998997 897f7b-946f80 897771-59737d 978985-586374 8b
7e7b-6794ac 736e6d-69b4d0 e0dfdf-683434
d4b99e-98f3f6 d4b99e-98b6b9 847263-984754 816f61-987e8b 99867f-98939f 836c64-987783 b9aca9-7e6f7e 54
4744-607085 dedddd-51b4d0 e8e6e6-4f3434
d6ba9f-989b9d d6ba9f-98eaed 7a6c5c-98ddde 8c7d70-986e73 8f7165-986472 ad9993-988592 735c55-98717e b9
b6b5-985f75 edeae9-98b4d0 7b7876-983434
d8bca2-343144 d8bca2-34787b 776c61-34e6e8 82796f-34dfe0 967e6f-348f9b ad9a91-346e7d 817a75-34717f f6
f3f2-345e76 9d9b99-34b4d0 443127-343434
DeleteObject 1

I'm so close, yet a bit off with this now.
(edit) the variable textcolor is a typo, should be testcolor, code has nothing to do with text.

UINT64 PixelAlgorithm(int left, int top, int right, int bottom)
{
    HDC         hdcScreen = GetDC(NULL);;
    DWORD       color;
    DWORD       textcolor;
    UINT64      i64algor = 1u;
    UINT64      i641, i642;
    int         nStep = 1;
    int         width = right - left;
    int         height = bottom - top;

    HDC hdcCapture = CreateCompatibleDC(hdcScreen);
    std::cout << "CreateCompatibleDC " << hdcCapture << std::endl; // looks good

    HBITMAP hbmp = CreateCompatibleBitmap(hdcScreen, width, height);
    std::cout << "CreateCompatibleBitmap " << hbmp << std::endl; // looks good

    HGDIOBJ currentObj = SelectObject(hdcCapture, hbmp);
    std::cout << "SelectObject " << currentObj << std::endl; // looks good

    BOOL BB = BitBlt(hdcCapture, 0, 0, width, height, hdcScreen, left, top, SRCCOPY);
    std::cout << "BitBlt " << BB << std::endl; // looks good

    BITMAPINFO BMI;
    BMI.bmiHeader.biSize = sizeof(BMI.bmiHeader);
    BMI.bmiHeader.biWidth = width;
    BMI.bmiHeader.biHeight = 0 - (bottom - top);
    BMI.bmiHeader.biPlanes = 1;
    BMI.bmiHeader.biBitCount = 32;
    BMI.bmiHeader.biCompression = BI_RGB;

    RGBQUAD *pPixels = new RGBQUAD[(width * height) + width + height];

    std::cout << "pPixels size : " << (width)* (height) << std::endl;

    int GDB = GetDIBits(hdcCapture, hbmp, 0, height, pPixels, &BMI, DIB_RGB_COLORS);
    if (GDB == 0)
    {
        std::cout << GetLastError() << std::endl;
        std::cout << "GetDIBits " << GDB << std::endl; // looks good
    }

    int rowIndex = 0;
    int columnIndex = 0;
    for (int column = 0; column <= width; column++)
    {
        for (int row = 0; row <= height; row++)
        {
            color = GetPixel(hdcScreen, column, row);
            int index = (row * height) + column;
            textcolor = RGB(pPixels[index].rgbRed, pPixels[index].rgbGreen, pPixels[index].rgbBlue);

            // performing some calculations here, irrelevant to problem
            // which gives me the expected result when using color from GetPixel function.

            std::cout << (int)rowIndex << " ";
            std::cout  << color << " ";
            std::cout << textcolor;
            if (color == textcolor)
            {
                std::cout << " true" << std::endl;
            }
            else
            {
                std::cout << " false" << std::endl;
            }

            rowIndex++;
        }

    }
    ReleaseDC(NULL, hdcScreen);

    return 0;
}

This prints the colors side by side, to check if I'm test them in the correct order, which is very important. They are now almost exactly right but with some oddities, where the colors do not match. It appears that there are ten matches (true) then a mismatch (false) until the end then it just goes bonkers.
Here is the output.

CreateCompatibleDC 6D01204E
CreateCompatibleBitmap A10520C9
SelectObject 0185000F
BitBlt 1
pPixels size : 100
0 3421236 3421236 true
1 13677720 13677720 true
2 13677720 13677720 true
3 13743257 13743257 true
4 13743513 13743513 true
5 13809306 13809306 true
6 13875099 13875099 true
7 13941150 13941150 true
8 14072479 14072479 true
9 14204066 14204066 true
10 14270116 16645629 false
11 3421236 3421236 true
12 13677720 13677720 true
13 13677720 13677720 true
14 13743257 13743257 true
15 13743513 13743513 true
16 13809306 13809306 true
17 13875099 13875099 true
18 13941150 13941150 true
19 14072479 14072479 true
20 14204066 14204066 true
21 14270116 0 false
22 3421236 3421236 true
23 13677720 13677720 true
24 13677720 13677720 true
25 13743257 13743257 true
26 13743513 13743513 true
27 13809306 13809306 true
28 11507842 11507842 true
29 8680035 8680035 true
30 8023132 8023132 true
31 7826529 7826529 true
32 8022108 1248182 false
33 3421236 3421236 true
34 13677720 13677720 true
35 13677720 13677720 true
36 13743257 13743257 true
37 13217427 13217427 true
38 8153947 8153947 true
39 7364177 7364177 true
40 8482657 8482657 true
41 9207152 9207152 true
42 8550767 8550767 true
43 9075822 15745792 false
44 3421236 3421236 true
45 13677720 13677720 true
46 13677720 13677720 true
47 13282964 13282964 true
48 7233105 7233105 true
49 8417640 8417640 true
50 9011067 9011067 true
51 10061439 10061439 true
52 9400677 9400677 true
53 9862767 9862767 true
54 12102816 2643742 false
55 3421236 3421236 true
56 13677720 13677720 true
57 13677720 13677720 true
58 7956313 7956313 true
59 8220518 8220518 true
60 8747896 8747896 true
61 9009009 9009009 true
62 8612964 8612964 true
63 11377043 11377043 true
64 11377297 11377297 true
65 6969166 15242013 false
66 3421236 3421236 true
67 13677720 13677720 true
68 11310206 11310206 true
69 7627608 7627608 true
70 8221552 8221552 true
71 8417131 8417131 true
72 9931141 9931141 true
73 12168361 12168361 true
74 7560277 7560277 true
75 8485493 8485493 true
76 16250357 0 false
77 3421236 3421236 true
78 13677720 13677720 true
79 8745056 8745056 true
80 8286055 8286055 true
81 8615797 8615797 true
82 10458001 10458001 true
83 9141883 9141883 true
84 5523268 5523268 true
85 12170933 12170933 true
86 16184306 16184306 true
87 12631483 0 false
88 3421236 3421236 true
89 13677720 13677720 true
90 7692113 7692113 true
91 8286569 8286569 true
92 9602434 9602434 true
93 7496801 7496801 true
94 7564909 7564909 true
95 14605789 14605789 true
96 15592169 15592169 true
97 10328985 10328985 true
98 5853773 0 false
99 3421236 3421236 true
100 13677720 13677720 true
101 7757391 7757391 true
102 8352104 8352104 true
103 8220265 8220265 true
104 10194830 10194830 true
105 14737375 14737375 true
106 15263462 15263462 true
107 8091766 8091766 true
108 4469031 4469031 true
109 10788244 0 false
110 3421236 13677720 false
111 13677720 13677720 true
112 7691084 13743257 false
113 8021852 13743513 false
114 9404537 13809306 false
115 7759970 13875099 false
116 13816272 13941150 false
117 15658219 14072479 false
118 10723228 14204066 false
119 9402728 16645629 false
120 7630186 0 false

Edited 1 Year Ago by Suzie999

From line 45, you're exceeding the loop bounds, it should be

for (int column = 0; column < width; column++)
{
    for (int row = 0; row < height; row++)
    {
      //  
      //  
    }
}

Apart from that, I think you'll always find some discrepancies between the Screen DC and the DC that you blit it to.
I took a screen shot utilising GetDIBits. It looked exactly like my desktop, though there were differences between using GetPixel on the Screen DC and what was saved in my bitmap capture.

nullptr, thanks for your time sir, I was going outside the array bounds. this problem is now solved.

Nick Evan, the purpose is to test an image file (bmp) against an area of the screen. essentially, look for an image and return its coordinates if found.

This article has been dead for over six months. Start a new discussion instead.