Creating a HBITMAP from glReadPixels

最后都变了- 提交于 2019-12-25 02:24:08

问题


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?!?!


回答1:


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




回答2:


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.



来源:https://stackoverflow.com/questions/7158289/creating-a-hbitmap-from-glreadpixels

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!