GetDIBits returning senseless rgb values

Ok, im trying with GetDIBits but i cant make it work.
It always returns senseless values.
I think im missing the purpose of HDC here. Can someone explain this please? I mean, what's it for???
Note:
1) The image is a screenshot which i take just before running the code by pressing 'PrtScreen' button on the keyboard.
2) GetDIBits scans line 500 which, since im on a resolution of 1280x1024, is approximately in the middle of the screen.
3) Color depth is 32bits.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>
#include <windows.h>

using namespace std;

int main()
{

    HBITMAP hBitmap;

    if (OpenClipboard(NULL))
    {
        hBitmap = (HBITMAP)GetClipboardData(CF_DIB);
        if (hBitmap == NULL)
        {
            cout << "Failed to get the clipboard data.";
            return 0;
        }
    }
    else
    {
        cout << "Failed to open the clipboard!";
        return 0;
    }

    HDC hdc=CreateCompatibleDC(NULL);

    BITMAPINFO bmi;
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = 1280;
    bmi.bmiHeader.biHeight = 1;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32;
    bmi.bmiHeader.biCompression = BI_RGB;
    bmi.bmiHeader.biSizeImage = 0;
    bmi.bmiHeader.biXPelsPerMeter = 0;
    bmi.bmiHeader.biYPelsPerMeter = 0;
    bmi.bmiHeader.biClrUsed = 0;
    bmi.bmiHeader.biClrImportant = 0;
    BYTE scanned[4*1280];

    int returnValue = GetDIBits(hdc,hBitmap,500,1,scanned,&bmi,DIB_RGB_COLORS);

    int r = scanned[2401];
    int g = scanned[2402];
    int b = scanned[2403];

    cout << "returnValue = " << returnValue << "\n";
    cout << "r = " << r << "\n";
    cout << "g = " << g << "\n";
    cout << "b = " << b << "\n";

    CloseClipboard();
    return 0;
}
Last edited on
Check the old thread:
http://www.cplusplus.com/forum/beginner/26727/#msg143125

Instead, you could also request a CF_BITMAP - but that would require you to keep guessing the bitmap format and dimensions (or call GetObject to get them), so CF_DIB is the more convenient approach here.
Thanks a lot for that Athar, now im able to save the .bmp file.
But i still have problems with the rgb values. First, im trying to retrieve rgb values of single pixels, so filling the bitmapBits with the values of all is too much. Even scanning a single line as i was trying to do with GetDIBits is too much actually. For example, i would need only the rgb values of the 400th pixel on line 500. Only that. How to accomplish this without external libraries and through the clipboard?
Secondly, the following code im using now, still returns senseless rgb values.
What am i missing?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <windows.h>

using namespace std;

int main()
{
    BITMAPINFO* bitmapInfo;

    if (OpenClipboard(NULL))
    {
        bitmapInfo = (BITMAPINFO*)GetClipboardData(CF_DIB);
        if (bitmapInfo == NULL)
        {
            cout << "Failed to get the clipboard data.";
            return 1;
        }
    }
    else
    {
        cout << "Failed to open the clipboard!";
        return 1;
    }

    BYTE* bitmapBits=(BYTE*)bitmapInfo+sizeof(bitmapInfo->bmiHeader);

    int r = bitmapBits[2401];
    int g = bitmapBits[2402];
    int b = bitmapBits[2403];

    cout << "r = " << r << "\n";
    cout << "g = " << g << "\n";
    cout << "b = " << b << "\n";

    CloseClipboard();
    return 0;
}
Im using this site http://www.drpeterjones.com/colorcalc/ set to some color before i press "PrtScreen" but the returned rgb values are wrong.
This is fairly easy, although there are a few things to keep in mind:
1. Bitmaps are saved row-based.
2. When the height is positive, it is a bottom-up bitmap, that is, the last line comes first in memory.
3. A row must be aligned on a 4-byte boundary.
4. Color channel order is BGR (unless specified otherwise by BI_BITFIELDS masks).

To extract a single pixel, you can use this. If you want to extract several, you should move this code into a helper class and provide a member function getPixel.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    BYTE* bitmapBits=(BYTE*)bitmapInfo+sizeof(bitmapInfo->bmiHeader);
    if (bitmapInfo->bmiHeader.biCompression==BI_BITFIELDS)bitmapBits+=12;

    const int w=bitmapInfo->bmiHeader.biWidth;
    const int h=bitmapInfo->bmiHeader.biHeight;
    const bool topdownBitmap=h<0;
    const int bytesPerPixel=bitmapInfo->bmiHeader.biBitCount/8;
    const int scanLineLength=(topdownBitmap? -1 : 1)*((w*bytesPerPixel+3)/4*4);
    const int firstLineOffset=topdownBitmap? 0 : ((h-1)*scanLineLength);

    int x=399,y=499;
    const int pixelOffset=firstLineOffset-y*scanLineLength+x*bytesPerPixel;

    const int r=bitmapBits[pixelOffset+2];
    const int g=bitmapBits[pixelOffset+1];
    const int b=bitmapBits[pixelOffset];
Thanks again, it works as a charm.
Marking this topic as solved.
Topic archived. No new replies allowed.