【发布时间】:2012-07-27 04:43:32
【问题描述】:
我想将我的窗口的上下文转换为位图。我使用窗口通过触摸绘制基本线条。我遇到的问题是我的位图是黑色的。这可能是因为我没有正确获取设备上下文或做错了其他事情。
函数CreateBitmapInfoStruct和CreateBMPFile来自this MSDN example。
还要注意g_hWnd 是一个全局变量,它具有我要为其保存图片的窗口的句柄。
我的最终目标是能够将位图保存到我拥有的 mysql 字段 (BLOB) 中。这就是我原来的问题。无论如何,我首先尝试创建一个 BMP 文件。
我在这里和其他地方搜索过。在this MSDN example 之后,我在这里推荐了我找到的最佳解决方案。但是,它不起作用。
对于这个特定问题和/或将位图写入 mysql 表中的 blob 的任何帮助,将不胜感激。
这是我的代码:
HDC hDC = GetDC(g_hWnd);
LPRECT rect = (LPRECT)malloc(sizeof(RECT));
GetWindowRect(g_hWnd,rect);
int h = rect->right - rect->left;
int w = rect->bottom - rect->top;
LPRECT rect = (LPRECT)malloc(sizeof(RECT));
GetWindowRect(g_hWnd,rect);
HBITMAP hBmp = CreateCompatibleBitmap(hDC,w,h);
PBITMAPINFO pbmi;
pbmi = CreateBitmapInfoStruct(g_hWnd,hBmp);
CreateBMPFile(g_hWnd, TEXT("c:\\TEMPO\\TestG2.bmp"), pbmi,
hBmp, hDC) ;
ReleaseDC(g_hWnd,hDC);
DeleteObject(hBmp);
DeleteObject(pbmi);
if (rect != nullptr)
free(rect);
编辑:
截屏(getDC)的实际答案是修改this sample in MSDN。
我已经修改了这里的示例(删除了拉伸)请注意,仍然使用 goto,我将删除它。
关于 GOTO 的注释...虽然我不使用它,但我也不认为它是一个问题。我认为关于 GOTO 语句已经做了太多......就像在汇编中,我们不会做 goto (JUMPS)
代码如下:
void saveBitmap()
{
HDC hdcScreen;
HDC hdcWindow;
HDC hdcMemDC = NULL;
HBITMAP hbmScreen = NULL;
BITMAP bmpScreen;
// Retrieve the handle to a display device context for the client
// area of the window.
hdcScreen = GetDC(NULL);
hdcWindow = GetDC(g_hWnd);
// Create a compatible DC which is used in a BitBlt from the window DC
hdcMemDC = CreateCompatibleDC(hdcWindow);
if(!hdcMemDC)
{
goto done;
}
RECT rcClient;
GetClientRect(g_hWnd, &rcClient);
hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right-rcClient.left,
rcClient.bottom-rcClient.top);
if(!hbmScreen)
{
goto done;
}
SelectObject(hdcMemDC,hbmScreen);
if(!BitBlt(hdcMemDC,
0,0,
rcClient.right-rcClient.left, rcClient.bottom-rcClient.top,
hdcWindow,
0,0,
SRCCOPY))
{
goto done;
}
GetObject(hbmScreen,sizeof(BITMAP),&bmpScreen);
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmpScreen.bmWidth;
bi.biHeight = bmpScreen.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 *
bmpScreen.bmHeight;
// Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that
// call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc
// have greater overhead than HeapAlloc.
HANDLE hDIB = GlobalAlloc(GHND,dwBmpSize);
char *lpbitmap = (char *)GlobalLock(hDIB);
// Gets the "bits" from the bitmap and copies them into a buffer
// which is pointed to by lpbitmap.
GetDIBits(hdcWindow, hbmScreen, 0,
(UINT)bmpScreen.bmHeight,
lpbitmap,
(BITMAPINFO *)&bi, DIB_RGB_COLORS);
// A file is created, this is where we will save the screen capture.
HANDLE hFile = CreateFile(L"c:\\tempo\\captureqwsx.bmp",
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
// Add the size of the headers to the size of the bitmap to get the total file size
DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER);
//Offset to where the actual bitmap bits start.
bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) +
(DWORD)sizeof(BITMAPINFOHEADER);
//Size of the file
bmfHeader.bfSize = dwSizeofDIB;
//bfType must always be BM for Bitmaps
bmfHeader.bfType = 0x4D42; //BM
DWORD dwBytesWritten = 0;
WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
//Unlock and Free the DIB from the heap
GlobalUnlock(hDIB);
GlobalFree(hDIB);
//Close the handle for the file that was created
CloseHandle(hFile);
//Clean up
done:
DeleteObject(hbmScreen);
DeleteObject(hdcMemDC);
ReleaseDC(NULL,hdcScreen);
ReleaseDC(g_hWnd,hdcWindow);
}
【问题讨论】:
-
我认为我必须在执行此操作时重新绘制设备上下文。就像我在 WM_PAINT 下做的一样。我要到星期二才能检查,但我有这样的感觉。同时,我觉得如果内容是在windows中绘制的,肯定有直接的获取方式。
-
if (rect != nullptr)nullptr?那是本地变量吗?或者这是否表明您正在使用托管 C++ 做某事?另外,您要声明rect两次,这将导致编译器错误。我建议不要使用malloc创建LPRECT,而是在堆栈上声明一个本地RECT并传递&rect。 -
nullptr 是 c++ 11 的一部分,其中一些适用于 vs 2010。没有托管代码 oj
-
由于复制粘贴错误,lprect 被声明了两次。
-
当然是的。 C++11。我的错,谢谢你的澄清。
标签: c++ winapi bitmap gdi+ gdi