从 glReadPixels 创建 HBITMAP
Posted
技术标签:
【中文标题】从 glReadPixels 创建 HBITMAP【英文标题】:Creating a HBITMAP from glReadPixels 【发布时间】:2011-08-23 08:39:43 【问题描述】:我需要根据 glReadPixels() 调用返回的数据创建 HBITMAP:
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 中?!?!
【问题讨论】:
我的GDI32技能有点生疏了,但是你看过CreateDIBitmap吗?我认为应该只是CreateDIBitmap(hDC,&header,CBM_INIT,pPixelData,&info,DIB_RGB_COLORS)
我已经尝试过使用 CreateDIBitmap,但它对我不起作用。我最终使用了 BITMAPFILEHEADER 和 BITMAPINFOHEADER 并将其直接写入 .bmp。如果我能够获得 HBITMAP 会更好,但没关系。回到 C# 是...
【参考方案1】:
您是否使用正确的参数调用函数。查看函数的文档:http://msdn.microsoft.com/en-us/library/dd183491(v=vs.85).aspx。好像您已经交换了参数顺序并正在传递一个指向数据指针的指针。
-蒂莫
【讨论】:
不,不是这样,即使交换参数并传递指针也没有给我任何东西。我找到了一种获取 HANDLE 的方法(更新了示例),但现在不知道如何将它放入 HBITMAP【参考方案2】:非常老的帖子,但我想给出一个答案,至少将其保留为存储库。
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。此外,您可能需要确保您正在复制区域。上面的代码假定区域与视口匹配。
【讨论】:
以上是关于从 glReadPixels 创建 HBITMAP的主要内容,如果未能解决你的问题,请参考以下文章
将 HBITMAP 句柄从非托管代码传递到托管代码以创建 System.Drawing.Bitmap 的安全性
如何从 HBITMAP 转换为 .NET 的 Bitmap 类?
OpenGL ES glReadPixels exc_bad_access