You need to take a screenshot and write its RGB data to the buffer (BYTE *, unsigned char *, string is not important). No need to save the file, no BMP headers needed - just an RGB array.

How to do it in C ++ with the minimum possible execution time and the lowest cost of system resources?

PS: runtime - Windows. I tried glReadPixels () - but the result is a black screen. GDI is slow and I still do not understand how to get RGB with it. And the GDI mouse cursor does not capture

  • which platform? - mymedia
  • 2
    In c ++ there are no built-in tools for working with images, or making a copy of the screen in particular. Specify which OS you are running and which libraries you use. - αλεχολυτ
  • Wednesday - Windows. I would like to get a consultation about the libraries - in the question I added a description of the problems I encountered - Iceman
  • getDC(0) - gives the screen context and can be copied. Here is an example of cyberforum.ru/win-api/thread877306.html in nete. - nick_n_a February
  • I know about GetDC, CreateCompatibleDC, BitBlt ... How can I extract a string buffer of RGB values ​​from all of this ??? - Iceman

3 answers 3

From here :

 /* Globals */ int ScreenX = GetDeviceCaps(GetDC(0), HORZRES); int ScreenY = GetDeviceCaps(GetDC(0), VERTRES); BYTE* ScreenData = new BYTE[3*ScreenX*ScreenY]; void ScreenCap() { HDC hdc = GetDC(GetDesktopWindow()); HDC hdcMem = CreateCompatibleDC (hdc); HBITMAP hBitmap = CreateCompatibleBitmap(hdc, ScreenX, ScreenY); BITMAPINFOHEADER bmi = {0}; bmi.biSize = sizeof(BITMAPINFOHEADER); bmi.biPlanes = 1; bmi.biBitCount = 24; bmi.biWidth = ScreenX; bmi.biHeight = -ScreenY; bmi.biCompression = BI_RGB; bmi.biSizeImage = ScreenX * ScreenY; SelectObject(hdcMem, hBitmap); BitBlt(hdcMem, 0, 0, ScreenX, ScreenY, hdc, 0, 0, SRCCOPY); GetDIBits(hdc, hBitmap, 0, ScreenY, ScreenData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS); DeleteDC(hdcMem); ReleaseDC(NULL, hdc); } inline int PosR(int x, int y) { return ScreenData[3*((y*ScreenX)+x)+2]; } inline int PosG(int x, int y) { return ScreenData[3*((y*ScreenX)+x)+1]; } inline int PosB(int x, int y) { return ScreenData[3*((y*ScreenX)+x)]; } 
  • Accordingly, the color of the pikel via PosR, PosG, PosB - Daniel Protopopov

Decided so far with the help of gdi32:

 void CaptureScreen(){ // Определение контекстов HDC ScreenDC = GetDC(0); HDC MemoryDC = CreateCompatibleDC(ScreenDC); // Фиксация размеров экрана int ScreenWidth = GetSystemMetrics(SM_CXSCREEN); int ScreenHeight = GetSystemMetrics(SM_CYSCREEN); // Создание и частичное заполнение структуры формата BITMAPINFO BMI; BMI.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); BMI.bmiHeader.biWidth = ScreenWidth; BMI.bmiHeader.biHeight = -ScreenHeight; // Отрицательное значение высоты, чтобы изображение не было перевёрнутым BMI.bmiHeader.biSizeImage = ScreenWidth * ScreenHeight * 3; // Ширина * Высота * Количество_цветов_на_пиксель BMI.bmiHeader.biCompression = BI_RGB; BMI.bmiHeader.biBitCount = 24; BMI.bmiHeader.biPlanes = 1; ScreenshotSize = BMI.bmiHeader.biSizeImage; // ScreenshotSize - глобальная переменная типа int, может меняться в ходе выполнения программы unsigned char *ImageBuffer; // Указатель на блок данных BGR, управляемый HBITMAP (да, именно BGR - не RGB) HBITMAP hBitmap = CreateDIBSection(ScreenDC,&BMI,DIB_RGB_COLORS,(void**)&ImageBuffer,0,0); SelectObject(MemoryDC, hBitmap); BitBlt(MemoryDC, 0, 0, ScreenWidth, ScreenHeight, ScreenDC , 0, 0, SRCCOPY); // Контексты больше не нужны DeleteDC(MemoryDC); ReleaseDC(NULL, ScreenDC); // Если требуется RGB вместо BGR - следующий цикл перевернёт нужные байты for(int i = 0; i < ScreenshotSize; i += 3){ unsigned char ColorValue = ImageBuffer[i]; ImageBuffer[i] = ImageBuffer[i + 2]; ImageBuffer[i + 2] = ColorValue; } // Используем ImageBuffer как нам хочется... после удаляем его хендлер (HBITMAP) для избежания утечки памяти DeleteObject(hBitmap); } 

Faster, probably, will be only DirectX or OpenGL, but with the latter there was already an unsuccessful screenshot experience, and I don’t yet know how to get data directly from the graphical output

  • The ImageBuffer pointer must be previously prepared, i.e. at the time you call CreateDIBSection there must be a valid pointer to a block of memory of the desired size. If your program does not crash with CreateDIBSection, then you are very lucky. Accordingly, if your memory block is not allocated, then what are you trying to delete with the help of delete? - insolor
  • As for speed, it is unlikely that WinAPI can be made faster. I would say that this method, on the contrary, is relatively fast (if compared with the same GetPixel). - insolor
  • I was stupid - deleted ImageBuffer instead of DeleteObject (hBitmap). Now everything works well and memory does not leak. But still tormented by the question, is it really impossible to capture what you see on the monitor using OpenGL? - Iceman
  • with the help of OpenGL, in theory, it is possible, but I didn’t work with it) - insolor
  • It turns out I forgot how CreateDIBSection works. Yes, that's right, you don’t need to allocate memory in advance; the function itself will put a pointer to a data block in the ImageBuffer. And then just do a DeleteObject for the hBitmap object. - insolor

You can try through COLORREF and GetPixel, that is, get the display context through GetDC, and then through GetPixel read the color of the pixel.

 HDC dc = GetDC(); COLORREF color = GetPixel(dc,x,y); 
  • If you need an entire image, then instead of GetPixel it is better to use BitBlt . - ߊߚߤߘ
  • GetPixel seems easy and simple, but it works like hell. 400 bytes it received a couple of seconds, and the display FullHD 4 million bytes - the program hung blankly when I got the pixels in the loop. - Iceman
  • Such things should be done in a separate thread - vp_arth