GetDIBits 返回所有值为 0 的数组

Posted

技术标签:

【中文标题】GetDIBits 返回所有值为 0 的数组【英文标题】:GetDIBits returns array with all values 0 【发布时间】:2021-06-08 18:15:41 【问题描述】:

我需要在屏幕上找到一些图像。我决定做一个简单的比较循环。

我发现this answer似乎有帮助,写了下一段代码:

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
    
  

两个问题:

    我的屏幕分辨率是 1280x800=1 024 000 px,MyBMInfo.bmiHeader.biSizeImage 等于 4 096 000。是 rgba 还是什么? 主要问题:虽然,没有错误,而且我在上一个问题中提到的值不为零,但是在代码底部的循环中,lpPixels的所有值都是零,我没有得到任何输出。为什么?

【问题讨论】:

也许是个愚蠢的问题......但是你在哪里将屏幕的像素值复制到你的 hdc 中? hdcSource(屏幕)和hdc(您的本地DC/位图)之间不应该有BitBlt或类似的吗? 您正在从全新的位图中提取数据。尝试使用 BitBlt 将一些数据从 hdcSource 复制到 hdc 和上面的cmets一样,不需要中间兼容位图。你可以使用CreateDIBSection创建一个DIB并直接从屏幕blit到那个。 @AdrianMole @BenVoight 我试一试BitBlt @BenVoigt 添加了BitBlt(hdc, 0, 0, xw, yw, hdcSource, 0, 0, SRCCOPY); 并且没有任何改变。 xwyw 是窗口的宽度和高度。 【参考方案1】:

对于不透明的屏幕数据,可以简单地将第四个字节(Alpha)设置为255,即不透明。

GetDIBits得到的位图数据的颜色格式写在BGR中(lpPixels参数)。如果我们想用 RGB 格式将数据分配给一个字节数组,我们需要进行一些转换。

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)
    

更新:

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];


【讨论】:

感谢您的回答。您能否也为我的第二个问题指定解决方案,例如BitBlt @Thawbkisavv 我更新了我的答案。我使用CreateDIBSectionBitBlt 制作了一个示例。

以上是关于GetDIBits 返回所有值为 0 的数组的主要内容,如果未能解决你的问题,请参考以下文章

GetDIBits 返回兼容位图的无效颜色数组

如何获得所有选中的节点jstree

处理 GetDIBits() 返回的像素缓冲区的正确方法是啥?

C++ 怎么编写一个字符串中某个字符出现n次的所有位置,返回值为指针数组,

LeetCode第二十七题-删除数组指定元素

如果数组中的所有值都为真(字符串)并且其中一个值为假(字符串),则如何返回布尔值 true 停止使用 Javascript 进行检查