【问题标题】:Win32 Create Bitmap from Device Context To File and/or BLOBWin32 从设备上下文创建位图到文件和/或 BLOB
【发布时间】:2012-07-27 04:43:32
【问题描述】:

我想将我的窗口的上下文转换为位图。我使用窗口通过触摸绘制基本线条。我遇到的问题是我的位图是黑色的。这可能是因为我没有正确获取设备上下文或做错了其他事情。

函数CreateBitmapInfoStructCreateBMPFile来自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


【解决方案1】:

您可以使用GetDIBits()。 该函数将图像像素数据复制到您自己分配的内存中。

有关更多详细信息和说明,请参阅GetDIBits and loop through pixels using X, Y

【讨论】:

  • 一个关于句柄的问题:HANDLE hSource = ?应该是HBITMAP,还是HBITMAP = CreateCompatibleBitmap(...)?
  • 根据文档第二个参数确实是HBITMAP
猜你喜欢
  • 2013-09-15
  • 1970-01-01
  • 2016-01-15
  • 2013-05-04
  • 2021-01-02
  • 1970-01-01
  • 2011-03-23
  • 1970-01-01
  • 2015-07-26
相关资源
最近更新 更多