C ++ Getting RGB from hBitmap

Working with bitmaps is very useful for me, so I really struggle with the online tutorials and strategies that I read. Basically my goal is to scan the screen for a specific RGB value. I believe that the steps for this are to capture the screen in hBitmap and then create an array of RGB values ​​from it through which I can scan.

I started with GetPixel, but it is very slow. The solution was to use GetDIBits, which creates an array of RGB values. The problem is that it returns weird and possibly random RGB values.

I am using the following code that I found from another tutorial:

/* Globals */ int ScreenX = GetDeviceCaps(GetDC(0), HORZRES); int ScreenY = GetDeviceCaps(GetDC(0), VERTRES); BYTE* ScreenData = new BYTE[3*ScreenX*ScreenY]; void ScreenCap() { HDC hdc = GetDC(GetDesktopWindow()); HDC hdcMem = CreateCompatibleDC (hdc); HBITMAP hBitmap = CreateCompatibleBitmap(hdc, ScreenX, ScreenY); BITMAPINFOHEADER bmi = {0}; bmi.biSize = sizeof(BITMAPINFOHEADER); bmi.biPlanes = 1; bmi.biBitCount = 24; bmi.biWidth = ScreenX; bmi.biHeight = -ScreenY; bmi.biCompression = BI_RGB; bmi.biSizeImage = ScreenX * ScreenY; SelectObject(hdcMem, hBitmap); BitBlt(hdcMem, 0, 0, ScreenX, ScreenY, hdc, 0, 0, SRCCOPY); GetDIBits(hdc, hBitmap, 0, ScreenY, ScreenData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS); DeleteDC(hdcMem); ReleaseDC(NULL, hdc); } inline int PosR(int x, int y) { return ScreenData[3*((y*ScreenX)+x)+2]; } inline int PosG(int x, int y) { return ScreenData[3*((y*ScreenX)+x)+1]; } inline int PosB(int x, int y) { return ScreenData[3*((y*ScreenX)+x)]; } 

I am testing this with the following code. I pressed Shift to invoke ScreenCap, and then move the cursor to the desired location and press Space to see what RGB value is in that place. Am I completely nuts?

 int main() { while ( true ) { if (GetAsyncKeyState(VK_SPACE)){ // Print out current cursor position GetCursorPos(&p); printf("X:%d Y:%d \n",px,py); // Print out RGB value at that position int r = PosR(px, py); int g = PosG(px, py); int b = PosB(px, py); printf("r:%dg:%db:%d \n",r,g,b); } else if (GetAsyncKeyState(VK_ESCAPE)){ printf("Quit\n"); break; } else if (GetAsyncKeyState(VK_SHIFT)){ ScreenCap(); printf("Captured\n"); } } system("PAUSE"); return 0; } 
+6
source share
2 answers

The problem is that your screen actually has a depth of 32 bits, not 24. The code below will give you the desired result:

 /* Globals */ int ScreenX = 0; int ScreenY = 0; BYTE* ScreenData = 0; void ScreenCap() { HDC hScreen = GetDC(NULL); ScreenX = GetDeviceCaps(hScreen, HORZRES); ScreenY = GetDeviceCaps(hScreen, VERTRES); HDC hdcMem = CreateCompatibleDC(hScreen); HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, ScreenX, ScreenY); HGDIOBJ hOld = SelectObject(hdcMem, hBitmap); BitBlt(hdcMem, 0, 0, ScreenX, ScreenY, hScreen, 0, 0, SRCCOPY); SelectObject(hdcMem, hOld); BITMAPINFOHEADER bmi = {0}; bmi.biSize = sizeof(BITMAPINFOHEADER); bmi.biPlanes = 1; bmi.biBitCount = 32; bmi.biWidth = ScreenX; bmi.biHeight = -ScreenY; bmi.biCompression = BI_RGB; bmi.biSizeImage = 0;// 3 * ScreenX * ScreenY; if(ScreenData) free(ScreenData); ScreenData = (BYTE*)malloc(4 * ScreenX * ScreenY); GetDIBits(hdcMem, hBitmap, 0, ScreenY, ScreenData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS); ReleaseDC(GetDesktopWindow(),hScreen); DeleteDC(hdcMem); DeleteObject(hBitmap); } inline int PosB(int x, int y) { return ScreenData[4*((y*ScreenX)+x)]; } inline int PosG(int x, int y) { return ScreenData[4*((y*ScreenX)+x)+1]; } inline int PosR(int x, int y) { return ScreenData[4*((y*ScreenX)+x)+2]; } bool ButtonPress(int Key) { bool button_pressed = false; while(GetAsyncKeyState(Key)) button_pressed = true; return button_pressed; } int main() { while (true) { if (ButtonPress(VK_SPACE)) { // Print out current cursor position POINT p; GetCursorPos(&p); printf("X:%d Y:%d \n",px,py); // Print out RGB value at that position std::cout << "Bitmap: r: " << PosR(px, py) << " g: " << PosG(px, py) << " b: " << PosB(px, py) << "\n"; } else if (ButtonPress(VK_ESCAPE)) { printf("Quit\n"); break; } else if (ButtonPress(VK_SHIFT)) { ScreenCap(); printf("Captured\n"); } } system("PAUSE"); return 0; } 
+8
source

The size of your image is in pixels ; it must be in bytes.

 **bmi.biSizeImage = ScreenX * ScreenY;** **bmi.biBitCount = 24;** bmi.biWidth = ScreenX; bmi.biHeight = -ScreenY; **bmi.biCompression = BI_RGB;** 

biSizeImage its specific unit bytes , and you specify RGB 3 bytes per pixel.

http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx

biSizeImage The size, in bytes , of the image. For BI_RGB bitmaps, this can be set to zero.

0
source

All Articles