Нужно сделать снимок экрана и записать его RGB-данные в буфер (BYTE*, unsigned char*, string - не важно). Не нужно сохранять файл, не нужны BMP-заголовки - просто массив RGB.
Как это сделать на C++ с минимально возможным временем выполнения и наименьшими затратами системных ресурсов?
PS: среда выполнения - Windows. Пробовал glReadPixels() - но в результате чёрный экран. GDI работает медленно и я так и не понял как с его помощью достать RGB. И курсор мыши GDI не захватывает
Отсюда:
/* 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)];
}
Решил пока так, при помощи средств 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);
}
Быстрее, наверно, будет только DirectX или OpenGL, но с последним уже был неудачный опыт скриншота, и я пока не знаю как получить данные прямо из графического вывода
Можно попробовать через COLORREF и GetPixel, т.е получить дисплейный контекст через GetDC, а потом через GetPixel прочитать цвет пикселя.
HDC dc = GetDC();
COLORREF color = GetPixel(dc,x,y);
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Есть таблица ForgeRock, которая содержит поле nameВ поле ForgeRock
Добрый деньНесколько разработчиков используют GIT в работе с сайтом, который сделан на WordPress
Как написать функцию проверки isGameOver() 5ти одинаковых символов подряд? Те