Search code examples
c++winapigdigetdibits

GetDIBits returns array with all values 0


I need to find some image on screen. I decided to make a simple comparing loop.

I found this answer that seems to be helpfull and wrote the next code:

void Capt()
{
  HDC hdcSource = GetDC(GetDesktopWindow()); // the source device context
  HDC hdc = CreateCompatibleDC(hdcSource);
  HBITMAP hSource = CreateCompatibleBitmap(hdcSource, xw, yw); // the bitmap selected into the device context

  SelectObject(hdc, hSource);

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

  // Get the BITMAPINFO structure from the bitmap
  if (0 == GetDIBits(hdc, hSource, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS))
  {
    mb("error1");
    IA(GetLastError());
  }

  // 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(hdc, hSource, 0, MyBMInfo.bmiHeader.biHeight,
    lpPixels, &MyBMInfo, DIB_RGB_COLORS))
  {
    mb("error2");
    IA(GetLastError());
  }

  DeleteObject(hSource);
  ReleaseDC(NULL, hdcSource);


  for (int i = 0, j=0; i < MyBMInfo.bmiHeader.biSizeImage&&j<100; i++)
  {
    if (lpPixels[i] != 0)
    {
      char buf[1024] = {};
      _itoa_s(lpPixels[i], buf, 10);
  
      //output
    }
  }
}

Two problems:

  1. My screen resolution is 1280x800=1 024 000 px, MyBMInfo.bmiHeader.biSizeImage is equal to 4 096 000. Is it rgba or what?
  2. The main issue: although, there is no errors, and the value I mentioned in previous problem is not zero, but in the loop at the bottom of code, all values of lpPixels are zero, I do not get any output. Why?

Solution

  • For screen data without transparency, you can simply set the fourth byte (Alpha) to 255, which means opaque.

    The color format of the bitmap data obtained by GetDIBits is written in BGR (lpPixels parameter). If we want to assign data to a byte array using RGB format, we need to perform some conversion.

    e.p.

    for (size_t i = 0; i < myWidth * myHeight; i++)
        {
            size_t tempIndex = (i * 4);
    
            // The colors are in BGR-format (windows format)
            // Hence, the order is reversed
            rgbPixels[tempIndex] = bgrPixels[tempIndex + 2]; // r
            rgbPixels[tempIndex + 1] = bgrPixels[tempIndex + 1]; // g
            rgbPixels[tempIndex + 2] = bgrPixels[tempIndex]; // b
            rgbPixels[tempIndex + 3] = 255; // a (always 255)
        }
    

    Updated:

    HDC hdc, hdcTemp;
    RECT rect;
    BYTE* bitPointer;
    int x, y;
    int red, green, blue, alpha;
    
    hdc = GetDC(HWND_DESKTOP);
    GetWindowRect(hWND_Desktop, &rect);
    int MAX_WIDTH = rect.right;
    int MAX_HEIGHT = rect.bottom;
    
    hdcTemp = CreateCompatibleDC(hdc);
    BITMAPINFO bitmap;
    bitmap.bmiHeader.biSize = sizeof(bitmap.bmiHeader);
    bitmap.bmiHeader.biWidth = MAX_WIDTH;
    bitmap.bmiHeader.biHeight = MAX_HEIGHT;
    bitmap.bmiHeader.biPlanes = 1;
    bitmap.bmiHeader.biBitCount = 32;
    bitmap.bmiHeader.biCompression = BI_RGB;
    bitmap.bmiHeader.biSizeImage = MAX_WIDTH * 4 * MAX_HEIGHT;
    bitmap.bmiHeader.biClrUsed = 0;
    bitmap.bmiHeader.biClrImportant = 0;
    HBITMAP hBitmap2 = CreateDIBSection(hdcTemp, &bitmap, DIB_RGB_COLORS, (void**)(&bitPointer), NULL, NULL);
    SelectObject(hdcTemp, hBitmap2);
    BitBlt(hdcTemp, 0, 0, MAX_WIDTH, MAX_HEIGHT, hdc, 0, 0, SRCCOPY);
    
    for (int i=0; i<(MAX_WIDTH * 4 * MAX_HEIGHT); i+=4)
    {
        red = (int)bitPointer[i];
        green = (int)bitPointer[i+1];
        blue = (int)bitPointer[i+2];
        alpha = (int)bitPointer[i+3];
    
    }