Создание HBITMAP из glReadPixels

Мне нужно создать HBITMAP из данных, возвращаемых вызовом glReadPixels():

HDC hCompDC = CreateCompatibleDC(NULL);
HDC hDC = GetDC();

m_hClipboardBitmap = CreateCompatibleBitmap(hDC, size.cx, size.cy);

if ( m_hClipboardBitmap == NULL )
{
    throw runtime_error( "Unable to create bitmap." );
}

HBITMAP hOldBm = (HBITMAP) SelectObject( hCompDC, m_hClipboardBitmap );

int numberOfBytes = 4 * size.cx * size.cy; 
unsigned char *pPixelData = new unsigned char[numberOfBytes];

::glReadPixels(minimum.x, minimum.y, size.cx, size.cy, GL_BGRA, GL_UNSIGNED_BYTE, pPixelData);

Я пытался использовать:

BITMAPINFOHEADER header; 
header.biWidth = size.cx; 
header.biHeight = size.cy; 
header.biSizeImage = numberOfBytes; 
header.biSize = sizeof(BITMAPINFOHEADER); 
header.biPlanes = 1; 
header.biBitCount =  4 * 8; // RGBA 
header.biCompression = 0; 
header.biXPelsPerMeter = 0; 
header.biYPelsPerMeter = 0; 
header.biClrUsed = 0; 
header.biClrImportant = 0;

HANDLE handle = (HANDLE)::GlobalAlloc (GHND, sizeof(BITMAPINFOHEADER) + numberOfBytes); 

if(handle != NULL) 
{ 
    char *pData = (char *) ::GlobalLock((HGLOBAL)handle); 

    memcpy(pData,&header,sizeof(BITMAPINFOHEADER)); 
    memcpy(pData + sizeof(BITMAPINFOHEADER), pPixelData, numberOfBytes); 

    ::GlobalUnlock((HGLOBAL)handle);

    OpenClipboard(); 
    EmptyClipboard(); 
    SetClipboardData(CF_DIB, handle); 
    CloseClipboard();
}

И это вставляется в mspaint нормально (так что данные в порядке), но как, черт возьми, я могу получить их в HBITMAP?!?!


person user907285    schedule 23.08.2011    source источник
comment
Мои навыки GDI32 немного заржавели, но вы смотрели на Создать DIBbitmap? Я думаю, что это должно быть просто CreateDIBitmap(hDC,&header,CBM_INIT,pPixelData,&info,DIB_RGB_COLORS)   -  person user786653    schedule 24.08.2011
comment
Я уже пытался использовать CreateDIBitmap, но у меня это не сработало. В итоге я использовал BITMAPFILEHEADER и BITMAPINFOHEADER и напрямую записал их в .bmp. Было бы лучше, если бы я смог получить HBITMAP, но неважно. Вернемся к С#, это...   -  person user907285    schedule 25.08.2011


Ответы (2)


Вы вызываете функцию с правильными параметрами. Ознакомьтесь с документацией по этой функции: http://msdn.microsoft.com/en-us/library/dd183491(v=vs.85).aspx. Похоже, вы поменяли порядок параметров и передаете указатель на указатель на данные.

-Тимо

person Timo Heinäpurola    schedule 23.08.2011
comment
Нет, это не так, даже замена параметров и просто передача указателя мне ничего не дают. Я нашел способ получить HANDLE (обновил пример), но теперь не знаю, как получить это в HBITMAP - person user907285; 24.08.2011

Очень старая ветка, но я хотел дать ответ, по крайней мере, чтобы сохранить его как репозиторий.

void WriteOpenGLPixelsToHBITMAP( HBITMAP dstHBITMAP, HDC dstDC, SIZE dims )
{

    BITMAPINFO bitmapInfo;
    {
        ::memset( &bitmapInfo, 0, sizeof( BITMAPINFO ) );
        bitmapInfo.bmiHeader.biSize        = sizeof( BITMAPINFOHEADER );
        bitmapInfo.bmiHeader.biPlanes      = 1;
        bitmapInfo.bmiHeader.biBitCount    = 32;
        bitmapInfo.bmiHeader.biCompression = BI_RGB;
        bitmapInfo.bmiHeader.biWidth       = dims.cx;
        bitmapInfo.bmiHeader.biHeight      = dims.cy;
        bitmapInfo.bmiHeader.biSizeImage   = dims.cx * dims.cy * 4; // Size 4, assuming RGBA from OpenGL
    }

    void    *bmBits = NULL;
    HDC     memDC   = ::CreateCompatibleDC( dstDC );
    HBITMAP memBM   = ::CreateDIBSection( NULL, &bitmapInfo, DIB_RGB_COLORS, &bmBits, NULL, 0 );


    ::glReadPixels( 0,
                    0,
                    dims.cx,
                    dims.cy,
                    GL_BGRA_EXT,
                    GL_UNSIGNED_BYTE,
                    bmBits );
    HGDIOBJ prevBitmap = ::SelectObject( memDC, memBM );
    HGDIOBJ obj        = ::SelectObject( dstDC, dstHBITMAP );

    // Remember that OpenGL origin is at bottom, left, but bitmaps are top, left
    if ( false == BitBlt( dstDC, 0 /*left*/, dims.cy /*top*/, dims.cx, dims.cy, memDC, 0, 0, SRCCOPY ) )
    {
        assert( false && "Failed to write pixels to HBitmap from OpenGL glReadPixels" );
    }

    ::SelectObject( memDC, prevBitmap );
    ::DeleteObject( memBM );
    ::DeleteDC( memDC );                    
}

Как уже упоминалось, помните об инвертированном изображении. Вы можете заменить SRCCOPY на SRCINVERT. Также вы можете убедиться, что копируете регионы. Приведенный выше код предполагает, что область соответствует области просмотра.

person Carlos RT    schedule 01.05.2014