开发者

Creating a HBITMAP from glReadPixels

I need to create a HBITMAP from data returned by a glReadPixels() call:

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

I tried using:

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

And that pastes into mspaint OK (so the data is good) but how on earth 开发者_如何转开发do I get it into a HBITMAP?!?!


Very old thread, but I wanted to give an answer, at least to keep it as a repository.

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

As mentioned, be aware of image being inverted. You can swap SRCCOPY for SRCINVERT. Also you might want to make sure you are copying regions. The code above assumes that the region matches the viewport.


Are you calling the function with the correct parameters. Check the documentation of the function: http://msdn.microsoft.com/en-us/library/dd183491(v=vs.85).aspx. Seems like you have swapped the parameter order and are passing a pointer to a pointer to the data.

-Timo

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜