c ++ считывание пикселей с помощью GetDIBits ()

Я пытаюсь создать функцию, которая эквивалентна функции Windows API GetPixel (), но я хочу создать растровое изображение моего экрана и затем прочитать этот буфер.

Это то, что у меня есть (в основном, копия, вставленная из поисков Google), когда я запускаю ее, она выводит только 0. Я думаю, что у меня есть большая часть этого права, и что моя проблема в том, что я не знаю, как читать переменную BYTE.

Итак, мой вопрос: что мне нужно сделать, чтобы он распечатывал некоторые случайные цвета (R, G или B) с помощью цикла for?

#include <Windows.h>
#include <iostream>
#include <math.h>
#include <stdio.h>

using namespace std;

int main() {

HDC hdc,hdcMem;

hdc = GetDC(NULL);
hdcMem = CreateCompatibleDC(hdc);

HBITMAP hBitmap = CreateCompatibleBitmap(hdc, 1680, 1050);

BITMAPINFO MyBMInfo = {0};
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
// Get the BITMAPINFO structure from the bitmap
if(0 == GetDIBits(hdcMem, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS)) {
cout << "error" << endl;
}

// create the bitmap buffer
BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage];

MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
MyBMInfo.bmiHeader.biBitCount = 32;
MyBMInfo.bmiHeader.biCompression = BI_RGB;
MyBMInfo.bmiHeader.biHeight = abs(MyBMInfo.bmiHeader.biHeight);

// get the actual bitmap buffer
if(0 == GetDIBits(hdc, hBitmap, 0, MyBMInfo.bmiHeader.biHeight, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS)) {
cout << "error2" << endl;
}

for(int i = 0; i < 100; i++) {
cout << (int)lpPixels[i] << endl;
}

return 0;
}
  • Windows 7
  • C :: B 13.12 (консольное приложение)
  • Компилятор: mingw32-gcc
  • Библиотека gdi32 связана

0

Решение

Как и было решено, я добавляю новый ответ с рабочим фрагментом кода (я добавил недостающую очистку lpPixels). Смотрите обсуждения в моем предыдущем ответе и ответе @enhzflep.

#include <Windows.h>
#include <iostream>
#include <math.h>
#include <stdio.h>
using namespace std;

HBITMAP GetScreenBmp( HDC hdc) {
// Get screen dimensions
int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);

// Create compatible DC, create a compatible bitmap and copy the screen using BitBlt()
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() {
HDC hdc = GetDC(0);

HBITMAP hBitmap = GetScreenBmp(hdc);

BITMAPINFO MyBMInfo = {0};
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);

// Get the BITMAPINFO structure from the bitmap
if(0 == GetDIBits(hdc, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS)) {
cout << "error" << endl;
}

// create the bitmap buffer
BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage];

// Better do this here - the original bitmap might have BI_BITFILEDS, which makes it
// necessary to read the color table - you might not want this.
MyBMInfo.bmiHeader.biCompression = BI_RGB;

// get the actual bitmap buffer
if(0 == GetDIBits(hdc, hBitmap, 0, MyBMInfo.bmiHeader.biHeight, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS)) {
cout << "error2" << endl;
}

for(int i = 0; i < 100; i++) {
cout << (int)lpPixels[i];
}

DeleteObject(hBitmap);
ReleaseDC(NULL, hdc);
delete[] lpPixels;
return 0;
}
3

Другие решения

По сути, вам нужно нарисовать несколько пикселей, чтобы получить результат, отличный от 0.

В настоящее время 4-я строка кода в вашем главном создает пустое (пустое, инициализированное 0) изображение. Затем вы получите информацию о размере этого изображения при первом обращении к GetDIBits, Затем вы получите фактические (пустые) пиксели при втором вызове GetDIBits,

Чтобы исправить это, просто загрузите растровый файл с диска в свой hBitmap и выберите это растровое изображение в свой hdcMem,

Т.е. изменить

HBITMAP hBitmap = CreateCompatibleBitmap(hdc, 1680, 1050);

что-то вроде этого.

HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, "xpButton.bmp", IMAGE_BITMAP, 0,0, LR_LOADFROMFILE);
HBITMAP old = (HBITMAP) SelectObject(hdcMem, hBitmap);

(Убедитесь, что вы используете правильное имя файла bmp. Mine находится в той же папке, что и файл .cpp, поскольку это «текущий» каталог при запуске через IDE. Если вы хотите запустить через проводник, поместите другую копию bmp в той же папке, что и ваш exe)

Вот bmp, который я использовал (который был преобразован в png после загрузки в SO):

введите описание изображения здесь

И вот первые 10 итераций в цикле.

255
5
253
0
255
5
253
0
255
5

Обратите внимание, что пиксель в точке 0,0 имеет цвет: rgb (253,5255), и это 8-битное изображение, поэтому альфа-канал отсутствует, следовательно, он имеет значение 0. Пиксели сохраняются как [BGRA], [BGRA] , [BGRA] и т. Д. И т. Д.
Я оставлю это вам, чтобы исправить (несуществующий) раздел очистки вашей программы. Windows освободит память, которую вы использовали здесь, но вы абсолютно не должны привыкать не освобождать память, которую вы распределили. 🙂

3

Ваш код кажется немного запутанным. Слишком много фрагментов, я думаю :).
Тем не менее, вы довольно близко
Первый вызов GetDIBits () предназначен для того, чтобы получить заполненные свойства растрового изображения, как предполагает комментарий в вашем коде.
Вы используете ненужный MemDC для этого — который, вероятно, из фрагмента, который хочет сделать BitBlt с экраном.

Затем вы можете использовать заполненную структуру, чтобы получить фактические пиксели растрового изображения со вторым вызовом GetDIBits (), но вы снова заменяете свойства жестко закодированными значениями, что делает первый вызов GetDIBits () бесполезным.

Итак: удалите MemDC — он вам не нужен — и замените hdcMem на hdc при первом вызове GetDIBits (), затем удалите все операторы, которые перезаписывают члены bmiHeader после первого вызова GetDIBits, и вы должны получить свои пиксели.

О, и, конечно же, не забудьте вызвать ReleaseDC () / DeleteObject () для dc и bitmap и удалить [] буфер 🙂

1
По вопросам рекламы [email protected]