2014-10-07 9 views
0

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

Это то, что у меня есть (чаще всего скопировано из поиска 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 (Application Console)
  • Компилятор: mingw32-НКУ
  • Библиотека gdi32 связана
+0

возможно дубликат [GetDIBits и проходным пикселей с использованием X, Y] (http://stackoverflow.com/questions/3688409/getdibits-and-loop-through-pixels-using-xy) – sashoalm

ответ

3

Как я уже сказал, я добавляю новый ответ с фрагментом рабочего кода (я добавил недостающую очистку 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; 
} 
1

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

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

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

О, и конечно, не забудьте позвонить ReleaseDC()/DeleteObject() на постоянном токе и битовой карты и удалить [] буфер :)

+0

я ценю ваш подробный ответ, но ваши предложенные изменения приводят к его сбою. http://codepad.org/EyRod1XA На каком сайте вы рекомендуете копировать вставку кода на C++? И, наконец, что произойдет, если я не удалю мои используемые объекты? Не удаляются ли они и автоматически освобождается память, когда код завершается? – Mandera

+0

Дальнейшие исследования: 'cout << (int) lpPixels [i] << endl;' вызывает его сбой, как правильно прочитать байтовую переменную? (Я немного осведомлен о «заполнении» и что он читается снизу справа) – Mandera

+1

Ничего. Я немного потрудился, и кажется, что @enhzflep прав, вы должны сначала скопировать пиксели через BitBlt() - I ' Я не знаю, почему сейчас, но мои знания GDI стали немного ржавыми. Я добавил фрагмент кода, который работает - он основан на вашем коде со вспомогательной функцией для получения скопированного растрового изображения: http://codepad.org/jQKJPm4u –

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); 

(убедитесь, что вы используете верное имя файла ВМР. Шахта существует в той же папке, что и файл .cpp, так как это «текущий» каталог при запуске через IDE.Если вы хотите запустить через проводник, поместите другую копию ВМРА в той же папке, что и ех)

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

enter image description here

И вот первые 10 итераций через петлю.

255 
5 
253 
0 
255 
5 
253 
0 
255 
5 

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

+0

Я ценю ваши усилия, но я хочу прочитать текущий экран, а не сохраненный образ BMP. – Mandera

+1

Не беспокойтесь. В этом случае сделайте растровое изображение, которое вы создаете тем же размером, что и экран, и выберите его в hdcMem. Теперь сделайте битбит из hdc рабочего стола в hdcMem. После этого вы можете перейти к строке 5 вашего основного. Вы можете использовать 'GetDC (HWND_DESKTOP)' для получения hdc рабочего стола. Затем вы можете битреть из этого hdc в ваш memdc. Simples. – enhzflep

+0

Не могли бы вы сделать еще один ответ, основанный на вашем комментарии, где вы подробно расскажете подробнее? – Mandera