C++ 如何读取屏幕像素?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2659932/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 00:15:58  来源:igfitidea点击:

How to read the screen pixels?

c++windowsscreen-capture

提问by Newbie

I want to read a rectangular area, or whole screen pixels. As if screenshot button was pressed.

我想读取矩形区域或整个屏幕像素。好像屏幕截图按钮被按下一样。

How i do this?

我怎么做?

Edit: Working code:

编辑:工作代码:

void CaptureScreen(char *filename)
{
    int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
    int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
    HWND hDesktopWnd = GetDesktopWindow();
    HDC hDesktopDC = GetDC(hDesktopWnd);
    HDC hCaptureDC = CreateCompatibleDC(hDesktopDC);
    HBITMAP hCaptureBitmap = CreateCompatibleBitmap(hDesktopDC, nScreenWidth, nScreenHeight);
    SelectObject(hCaptureDC, hCaptureBitmap); 

    BitBlt(hCaptureDC, 0, 0, nScreenWidth, nScreenHeight, hDesktopDC, 0,0, SRCCOPY|CAPTUREBLT); 

    BITMAPINFO bmi = {0}; 
    bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); 
    bmi.bmiHeader.biWidth = nScreenWidth; 
    bmi.bmiHeader.biHeight = nScreenHeight; 
    bmi.bmiHeader.biPlanes = 1; 
    bmi.bmiHeader.biBitCount = 32; 
    bmi.bmiHeader.biCompression = BI_RGB; 

    RGBQUAD *pPixels = new RGBQUAD[nScreenWidth * nScreenHeight]; 

    GetDIBits(
        hCaptureDC, 
        hCaptureBitmap, 
        0,  
        nScreenHeight,  
        pPixels, 
        &bmi,  
        DIB_RGB_COLORS
    );  

    // write:
    int p;
    int x, y;
    FILE *fp = fopen(filename, "wb");
    for(y = 0; y < nScreenHeight; y++){
        for(x = 0; x < nScreenWidth; x++){
            p = (nScreenHeight-y-1)*nScreenWidth+x; // upside down
            unsigned char r = pPixels[p].rgbRed;
            unsigned char g = pPixels[p].rgbGreen;
            unsigned char b = pPixels[p].rgbBlue;
            fwrite(fp, &r, 1);
            fwrite(fp, &g, 1);
            fwrite(fp, &b, 1);
        }
    }
    fclose(fp);

    delete [] pPixels; 

    ReleaseDC(hDesktopWnd, hDesktopDC);
    DeleteDC(hCaptureDC);
    DeleteObject(hCaptureBitmap);
}

采纳答案by Adrian McCarthy

Starting with your code and omitting error checking ...

从您的代码开始并省略错误检查......

// Create a BITMAPINFO specifying the format you want the pixels in.
// To keep this simple, we'll use 32-bits per pixel (the high byte isn't
// used).
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
bmi.bmiHeader.biWidth = nScreenWidth;
bmi.bmiHeader.biHeight = nScreenHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;

// Allocate a buffer to receive the pixel data.
RGBQUAD *pPixels = new RGBQUAD[nScreenWidth * nScreenHeight];

// Call GetDIBits to copy the bits from the device dependent bitmap
// into the buffer allocated above, using the pixel format you
// chose in the BITMAPINFO.
::GetDIBits(hCaptureDC,
            hCaptureBitmap,
            0,  // starting scanline
            nScreenHeight,  // scanlines to copy
            pPixels,  // buffer for your copy of the pixels
            &bmi,  // format you want the data in
            DIB_RGB_COLORS);  // actual pixels, not palette references

// You can now access the raw pixel data in pPixels.  Note that they are
// stored from the bottom scanline to the top, so pPixels[0] is the lower
// left pixel, pPixels[1] is the next pixel to the right,
// pPixels[nScreenWidth] is the first pixel on the second row from the
// bottom, etc.

// Don't forget to free the pixel buffer.
delete [] pPixels;

回答by Adrian McCarthy

Rereading your question, it sounds like we may have gotten off on a tangent with the screen capture. If you just want to check some pixels on the screen, you can use GetPixel.

重新阅读您的问题,听起来我们可能已经与屏幕截图相去甚远。如果您只想检查屏幕上的一些像素,可以使用GetPixel.

HDC hdcScreen = ::GetDC(NULL);
COLORREF pixel = ::GetPixel(hdcScreen, x, y);
ReleaseDC(NULL, hdcScreen);
if (pixel != CLR_INVALID) {
  int red = GetRValue(pixel);
  int green = GetGValue(pixel);
  int blue = GetBValue(pixel);
  ...
} else {
  // Error, x and y were outside the clipping region.
}

If you're going to read a lot of pixels, then you're better off with a screen capture and then using GetDIBits. Calling GetPixelzillions of times will be slow.

如果您要读取大量像素,那么最好使用屏幕截图,然后使用GetDIBits. 调用GetPixel无数次会很慢。

回答by Hans Passant

You make a screenshot with BitBlt(). The size of the shot is set with the nWidth and nHeight arguments. The upper left corner is set with the nXSrc and nYSrc arguments.

您使用 BitBlt() 制作屏幕截图。镜头的大小由 nWidth 和 nHeight 参数设置。左上角设置了 nXSrc 和 nYSrc 参数。

回答by Segy

You can use the code below to read the screen pixels:

您可以使用以下代码读取屏幕像素:

HWND desktop = GetDesktopWindow();
HDC desktopHdc = GetDC(desktop);
COLORREF color = GetPixel(desktopHdc, x, y);

回答by Mark Ransom

HBITMAP is not a pointer or an array, it is a handle that is managed by Windows and has meaning only to Windows. You must ask Windows to copy the pixels somewhere for use.

HBITMAP 不是指针或数组,它是一个由 Windows 管理的句柄,只对 Windows 有意义。您必须要求 Windows 将像素复制到某处以供使用。

To get an individual pixel value, you can use GetPixelwithout even needing a bitmap. This will be slow if you need to access many pixels.

要获取单个像素值,您可以使用GetPixel甚至不需要位图。如果您需要访问许多像素,这将很慢。

To copy a bitmap to memory you can access, use the GetDIBits function.

要将位图复制到您可以访问的内存中,请使用GetDIBits 函数