C++屏幕截图 - 如何读取位图?

C++ screen capture - how to read the bitmap?

本文关键字:读取 位图 屏幕截图 何读取 C++      更新时间:2023-10-16

我希望程序(用 c++ 编写(从屏幕上读取像素,但我得到的响应似乎很混乱,变量start指示鼠标的位置。正确的方法是什么? 我使用了工作正常的 GetPixel((,但我需要一个完整的位图来提高效率。这是代码:

#include <Windows.h>
#include <iostream>
#include <math.h>
#include <stdio.h>
using namespace std;
int nScreenWidth;
int nScreenHeight;
HBITMAP GetScreenBmp(HDC hdc) {
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() {
nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
HBITMAP hBitmap;
int times = 0;
while (!GetAsyncKeyState(VK_SPACE) && times<1000)
{
times++;
POINT p;
GetCursorPos(&p);
HDC hdc = GetDC(0);
hBitmap = GetScreenBmp(hdc);
BITMAPINFO MyBMInfo = {0};
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
if(0 == GetDIBits(hdc, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS)) {
cout << "error" << endl;
}
BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage];
MyBMInfo.bmiHeader.biCompression = BI_RGB;
if(0 == GetDIBits(hdc, hBitmap, 0, MyBMInfo.bmiHeader.biHeight, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS)) {
cout << "error2" << endl;
}
//**HERE** - position is wrong?
int start = (p.y*nScreenWidth+p.x)*4;
for(int i = start; i < start + 4; i+=4)
{
cout << "R:" << (int)lpPixels[i+2] << " G:" << (int)lpPixels[i+1] << " B:" << (int)lpPixels[i] << endl;
}
ReleaseDC(NULL, hdc);
delete[] lpPixels;
Sleep(1000);
}
DeleteObject(hBitmap);
return 0;
}

您正在强制BI_RGB压缩,您不妨设置前 6 个值并仅调用GetDIBits一次。由于位图高度从下到上开始,因此您必须为BITMAPINFOHEADER提供负高度,否则从下到上读取。

确保该过程是 DPI 感知的。最简单的方法(但不是首选方法(是调用SetProcessDPIAware()。对于每个hBitmap分配调用DeleteObject(hBitmap)

int main()
{
SetProcessDPIAware();
int width = GetSystemMetrics(SM_CXSCREEN);
int height = GetSystemMetrics(SM_CYSCREEN);
while(!GetAsyncKeyState(VK_SPACE))
{
HDC hdc = GetDC(0);
POINT p;
GetCursorPos(&p);
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP hbitmap = CreateCompatibleBitmap(hdc, width, height);
HGDIOBJ oldbmp = SelectObject(memdc, hbitmap);
BitBlt(memdc, 0, 0, width, height, hdc, 0, 0, SRCCOPY | CAPTUREBLT);
SelectObject(memdc, oldbmp);
DeleteDC(memdc);
//use GetPixel for testing
COLORREF c = GetPixel(hdc, p.x, p.y);
printf("%02X%02X%02Xn", GetRValue(c), GetGValue(c), GetBValue(c));
BITMAPINFO bi = { 0 };
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = width;
bi.bmiHeader.biHeight = -height;
bi.bmiHeader.biBitCount = 32; //32-bit bitmap
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biCompression = BI_RGB;
//allocate 4 bytes per pixel for 32-bit
BYTE* lpPixels = new BYTE[height * width * 4]; 
if(0 != GetDIBits(hdc, hbitmap, 0, height, lpPixels,
&bi, DIB_RGB_COLORS))
{
int i = (p.y * width + p.x) * 4;
printf("%02X%02X%02Xnn", 
lpPixels[i + 2], lpPixels[i + 1], lpPixels[i + 0]);
}
DeleteObject(hbitmap);
ReleaseDC(NULL, hdc);
delete[] lpPixels;
Sleep(1000);
}
return 0;
}