我注意到当我尝试运行BitBlt时,结果数据缓冲区在两方面是意外的:
- 沿着y轴翻转(原点似乎在左下方而不是左上方)
- 在每个RGBA分组中,R和B值似乎被交换。
对于第一个问题,我在使用命令提示符进行测试时注意到它;如果我的命令提示符在屏幕的左上角,那么只有当我的光标在左下角时,它才会显示它是黑色的。我必须通过将int offset = (y * monitor_width + x) * 4;
更改为int offset = ((monitor_height - 1 - y) * monitor_width + x) * 4;
来修复y轴的反转,这固定了像素位置问题,因为它在我预期的黑色处显示黑色。
然而,颜色仍然很强烈。我通过尝试获取已知像素的颜色来进行测试。我注意到每个蓝色像素都有非常高的R值,每个红色像素都有非常高的蓝色值。当我与现有的工具进行比较时,我发现每个像素的红色和蓝色值似乎都被切换了。起初我认为这是向后或字节对齐问题,但我也在一个不均匀的像素集群中进行了验证,以确保它选择了像素的正确位置,并且它做得很好,只是更换了颜色。
下面的完整简化代码(最初我的工具是获得我的光标位置和打印像素颜色通过热键按;这是一个简化的版本,得到一个特定的点)。
BYTE* my_pixel_data;
HDC hScreenDC = GetDC(GetDesktopWindow());
int BitsPerPixel = GetDeviceCaps(hScreenDC, BITSPIXEL);
HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
int monitor_width = GetSystemMetrics(SM_CXSCREEN);
int monitor_height = GetSystemMetrics(SM_CYSCREEN);
std::cout << std::format("monitor width height: {}, {}n", monitor_width, monitor_height);
BITMAPINFO info;
info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
info.bmiHeader.biWidth = monitor_width; // client_width;
info.bmiHeader.biHeight = monitor_height; // client_height;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biBitCount = BitsPerPixel;
info.bmiHeader.biCompression = BI_RGB;
HBITMAP hbitmap = CreateDIBSection(hMemoryDC, &info, DIB_RGB_COLORS, (void**)&my_pixel_data, 0, 0);
SelectObject(hMemoryDC, hbitmap);
BitBlt(hMemoryDC, 0, 0, monitor_width, monitor_height, hScreenDC, 0, 0, SRCCOPY);
int x = 12, y = 12;
int offset = ((monitor_height - 1 - y) * monitor_width + x) * 4;
std::cout << std::format("debug: ({}, {}): ({}, {}, {})n", x, y, (int)my_pixel_data[offset], (int)my_pixel_data[offset + 1], (int)my_pixel_data[offset + 2], (int)my_pixel_data[offset + 3]);
system("pause");
这个的输出将是debug: (12, 12): (199, 76, 133)
,即使另一个程序已经验证了颜色实际上是(133,76,199)。
我可以很容易地在我的代码中通过翻转y轴和切换每个R和B值来修复这个问题,程序将完美地工作。然而,我只是对这是如何发生的以及是否有一个更优雅的修复感到困惑。
我可以回答RGB(看起来Hans在评论中回答了倒Y轴)。记住,RGB是0xAARRGGBB存储的,所以在这个32位值中,BB是字节0,GG是字节1,RR是字节2(如果你使用它,alpha是字节3),所以当你在+0,+1和+2处索引时,你实际上得到了正确的值。当我们说RGB时,我们说的是与它们在内存中的存储顺序相反的颜色。