Search code examples
c++pixelbmpgetdibits

c++ read pixels with GetDIBits()


I'm trying to create a function which is equivalent to the windows API GetPixel() function, but I want to create a bitmap of my screen and then read that buffer.

This is what I've got (Mostly copy pasted from google searches), when I run it it only prints out 0's. I think I've got most of it right, and that my issue is that I don't know how to read the BYTE variable.

So my question is, what do I need to do in order to get it to print out some random colors (R,G or B) with my for loop?

#include <Windows.h>
#include <iostream>
#include <math.h>
#include <stdio.h>

using namespace std;

int main() {

    HDC hdc,hdcMem;

    hdc = GetDC(NULL);
    hdcMem = CreateCompatibleDC(hdc); 

    HBITMAP hBitmap = CreateCompatibleBitmap(hdc, 1680, 1050);

    BITMAPINFO MyBMInfo = {0};
    MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader); 
    // Get the BITMAPINFO structure from the bitmap
    if(0 == GetDIBits(hdcMem, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS)) {
        cout << "error" << endl;
    }

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

    MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
    MyBMInfo.bmiHeader.biBitCount = 32;  
    MyBMInfo.bmiHeader.biCompression = BI_RGB;  
    MyBMInfo.bmiHeader.biHeight = abs(MyBMInfo.bmiHeader.biHeight); 

    // get the actual bitmap buffer
    if(0 == GetDIBits(hdc, hBitmap, 0, MyBMInfo.bmiHeader.biHeight, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS)) {
        cout << "error2" << endl;
    }

    for(int i = 0; i < 100; i++) {
        cout << (int)lpPixels[i] << endl;
    }

    return 0;
}
  • Windows 7
  • C::B 13.12 (Console Application)
  • Compiler: mingw32-gcc
  • Library gdi32 linked

Solution

  • As agreed, I'm adding a new answer with the working code snippet (I added the missing cleanup of lpPixels). See the discussions in my previous answer and the one made by @enhzflep.

    #include <Windows.h>
    #include <iostream>
    #include <math.h>
    #include <stdio.h>
    using namespace std;
    
    HBITMAP GetScreenBmp( HDC hdc) {
        // Get screen dimensions
        int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
        int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
    
        // Create compatible DC, create a compatible bitmap and copy the screen using BitBlt()
        HDC hCaptureDC  = CreateCompatibleDC(hdc);
        HBITMAP hBitmap = CreateCompatibleBitmap(hdc, nScreenWidth, nScreenHeight);
        HGDIOBJ hOld = SelectObject(hCaptureDC, hBitmap); 
        BOOL bOK = BitBlt(hCaptureDC,0,0,nScreenWidth, nScreenHeight, hdc,0,0,SRCCOPY|CAPTUREBLT); 
    
        SelectObject(hCaptureDC, hOld); // always select the previously selected object once done
        DeleteDC(hCaptureDC);
        return hBitmap;
    }
    
    int main() {
        HDC hdc = GetDC(0);
    
        HBITMAP hBitmap = GetScreenBmp(hdc);
    
        BITMAPINFO MyBMInfo = {0};
        MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader); 
    
        // Get the BITMAPINFO structure from the bitmap
        if(0 == GetDIBits(hdc, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS)) {
            cout << "error" << endl;
        }
    
        // create the bitmap buffer
        BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage];
    
        // Better do this here - the original bitmap might have BI_BITFILEDS, which makes it
        // necessary to read the color table - you might not want this.
        MyBMInfo.bmiHeader.biCompression = BI_RGB;  
    
        // get the actual bitmap buffer
        if(0 == GetDIBits(hdc, hBitmap, 0, MyBMInfo.bmiHeader.biHeight, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS)) {
            cout << "error2" << endl;
        }
    
        for(int i = 0; i < 100; i++) {
            cout << (int)lpPixels[i];
        }
    
        DeleteObject(hBitmap);
        ReleaseDC(NULL, hdc);
        delete[] lpPixels;
        return 0;
    }