【发布时间】:2015-04-01 20:42:53
【问题描述】:
我在主窗口上有几个子窗口,有的是GDI窗口,有的是opengl渲染的窗口,一个功能是用一个矩形来捕捉图像(可能覆盖不同的窗口组合)。此功能在 windows xp 下运行良好。但是,在 windows 7 下,所有 opengl 渲染的窗口都是黑色的。我做了一些研究,有人说gdi不能通过window DC直接访问帧缓冲区,必须使用glReadPixels来组合位图。然而,这种方法很尴尬,因为我必须分别组合该矩形中的每个窗口。有人对我有更好的选择吗?
这是我捕获 bmp 的代码:
void MainWndClass::catchBmp(const char* path_fn, bool drawAreaOnly /*=0*/)
{
CDC *pDC=GetDC();
int BitPerPixel = pDC->GetDeviceCaps(BITSPIXEL);
int Left,Top,Width,Height;
if (drawAreaOnly)
{
Left = rBDWin.left;
Top = rBDWin.top;
Width = rBDWin.right-rBDWin.left;
Width = Width/4*4;
Height = rBDWin.bottom-rBDWin.top;
Height = Height/4*4;
}
else
{
Left=rbmpWin.left;
Top=rbmpWin.top;
Width=rbmpWin.right-rbmpWin.left;
Width=Width/4*4;
Height=rbmpWin.bottom-rbmpWin.top;
Height=Height/4*4;
}
CDC memDC;
memDC.CreateCompatibleDC(pDC);
CBitmap memBitmap, *oldmemBitmap;
memBitmap.CreateCompatibleBitmap(pDC, Width, Height);
//it seems does no work
//short bpp=24;
if(BitPerPixel>24) BitPerPixel=24;
memBitmap.SetBitmapBits(2,&BitPerPixel);
oldmemBitmap = memDC.SelectObject(&memBitmap);
//copy the bitmap from the pDC (source)
memDC.BitBlt(0, 0, Width, Height, pDC, Left, Top, SRCCOPY);
/*
CString title;
GetWindowText(title);
memDC.SetBkMode(TRANSPARENT);
memDC.TextOut(64,4,title);
*/
BITMAP bmp;
memBitmap.GetBitmap(&bmp);
if(bmp.bmBitsPixel>24)
{
bmp.bmBitsPixel=24;
//bmp.bmWidthBytes=bmp.bmWidth*3;
}
bmp.bmWidthBytes=bmp.bmWidth*(bmp.bmBitsPixel/8);
FILE *fp=NULL;
//path_fn+=".bmp";
fp=fopen((LPCTSTR)path_fn,"w+b");
BITMAPINFOHEADER bih = {0};
bih.biBitCount = bmp.bmBitsPixel;
bih.biCompression = BI_RGB;
bih.biHeight = bmp.bmHeight;
bih.biPlanes = 1;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biSizeImage = bmp.bmWidthBytes * bmp.bmHeight;
bih.biWidth = bmp.bmWidth;
BITMAPFILEHEADER bfh = {0};
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bfh.bfSize = bfh.bfOffBits + bmp.bmWidthBytes * bmp.bmHeight;
bfh.bfType = (WORD)0x4d42;
if(fp)
{
fwrite(&bfh, 1, sizeof(BITMAPFILEHEADER), fp);
fwrite(&bih, 1, sizeof(BITMAPINFOHEADER), fp);
}
byte * p = new byte[bmp.bmWidthBytes * bmp.bmHeight];
//copy the bits to the buffer
int ret=GetDIBits(memDC.m_hDC, (HBITMAP) memBitmap.m_hObject, 0, Height, p,
(LPBITMAPINFO) &bih, DIB_RGB_COLORS);
if(fp)
fwrite(p, 1, bmp.bmWidthBytes * bmp.bmHeight, fp);
delete [] p;
if(fp)
fclose(fp);
memDC.SelectObject(oldmemBitmap);
}
opengl窗口配置为:
PIXELFORMATDESCRIPTOR pixelDesc =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|
PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
24,
0,0,0,0,0,0,
0,
0,
0,
0,0,0,0,
32,//
0,
0,
PFD_MAIN_PLANE,
0,
0,0,0
};
我想再次强调一个事实: xp下可以,win7下不行(opengl窗口部分是黑色的)
【问题讨论】:
-
根据我的经验,这只是发生。有时,窗口在视频卡上的渲染和合成方式使得主处理器无法真正“看到”它。我知道当人们捕获游戏的屏幕截图或视频时,他们经常会因为这个问题而求助于专门的应用程序。捕获媒体播放器的屏幕截图时也会发生这种情况。它似乎因 Window 使用的操作系统、驱动程序和图形库而异。
-
是的。在任何规范或文档中都不能保证允许您通过 GDI 捕获 OpenGL 帧缓冲区的内容。它可能在某些情况下有效,但并非必须如此。实际上,它也不适用于 XP 的所有情况。
-
感谢 cmets,我想我必须使用其他程序来执行此操作,例如 ffmpeg。