This question already has answers here:
Save HBITMAP to *.bmp file using only Win32

(5 个回答)


6年前关闭。




好的,整个故事是,我试图在 C++ 中使用 Leptonica+Tesseract OCR 来截取屏幕截图,将其保存到 *.bmp 文件,然后将其加载回 OCR。我不需要经常执行此操作,但由于我似乎无法将屏幕截图数据直接复制到 Leptonica PIX 结构中,因此我需要先将其保存到文件中。实际上,最好是解决此问题。

这是我在网上找到的一些代码,试图帮助我。

屏幕盖:
HBITMAP ScreenCapture(){
  int width=100;
  int height=100;
  // get the device context of the screen
  HDC hScreenDC = CreateDC(L"DISPLAY", NULL, NULL, NULL);
  // and a device context to put it in
  HDC hMemoryDC = CreateCompatibleDC(hScreenDC);

  int x = GetDeviceCaps(hScreenDC, HORZRES);
  int y = GetDeviceCaps(hScreenDC, VERTRES);

  // maybe worth checking these are positive values
  HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, x, y);

  // get a new bitmap
  HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, hBitmap);

  BitBlt(hMemoryDC, 0, 0, width, height, hScreenDC, 0, 0, SRCCOPY);
  hBitmap = (HBITMAP)SelectObject(hMemoryDC, hOldBitmap);

  //GlobalAlloc(GPTR, hBitmap)

  WriteDIB(L"test.bmp", (HGLOBAL)hBitmap);

  // clean up
  DeleteDC(hMemoryDC);
  DeleteDC(hScreenDC);

  return hBitmap;
  // now your image is held in hBitmap. You can save it or do whatever with it
}

尝试编写函数:
BOOL WriteDIB( LPTSTR szFile, HANDLE hDIB)
{
  cout<<endl<<"Running save function";
  /*HANDLE hDIB=GlobalAlloc(GPTR, sizeof(hDIBtochange));//this doesn't work, the result is four. Also the HANDLE parameter's name would be changed to hDIBtochange, so that the rest of the function uses the old 'hDIB' throughout
  cout<<endl<<sizeof(hDIBtochange);*/
  BITMAPFILEHEADER  hdr;
  LPBITMAPINFOHEADER    lpbi;
  if (!hDIB)
    return FALSE;
  CFile file;
  if( !file.Open( szFile, CFile::modeWrite|CFile::modeCreate) )
    return FALSE;
  lpbi = (LPBITMAPINFOHEADER)hDIB;
  int nColors = 1 << lpbi->biBitCount;
  // Fill in the fields of the file header
  hdr.bfType        = ((WORD) ('M' << 8) | 'B');    // is always "BM"
  hdr.bfSize        = GlobalSize (hDIB) + sizeof( hdr );
  hdr.bfReserved1   = 0;
  hdr.bfReserved2   = 0;
  hdr.bfOffBits     = (DWORD) (sizeof( hdr ) + lpbi->biSize + nColors * sizeof(RGBQUAD));
  // Write the file header
  file.Write( &hdr, sizeof(hdr) );
  // Write the DIB header and the bits
  file.Write( lpbi, GlobalSize(hDIB) );
  return TRUE;
}

多年来无耻地抄袭人们的帖子。
好的!我面临的问题是,我似乎无法理解如何将 Hbitmap GlobalAlloc 转换为全局可访问的句柄,该句柄可以转换或与 LPBITMAPINFOHEADER 一起使用。
创建 lpbi 后,其中的每个字段都是 Visual Studio 2012 调试中的“无法读取内存”错误。尽管已创建,但它无法访问。

解决方案..
直接从 screencap 到 PIX,在内存中..
找到一种方法来保存到位图并定期创建它们以读取..
找到另一种更有意义的方式。

更喜欢第一个,但是,我在寻求解决方案,而不是第二个……或第三个。

如果您需要更多信息,我可以尝试提供。这主要归结为“我以前从未编写过这样的代码,而且我的类(class)中没有教过它,所以我正在努力学习”。

最佳答案

将 HBITMAP 保存到文件的一种更简单的方法是使用 GDI+。
这为您提供了能够保存为 Windows native 支持的任何格式的优势,同时使您免于使用甚至需要理解各种图像格式的麻烦。

在下面的示例中,我刚刚使用 LoadImage 作为加载预先存在的图像的一种快速而肮脏的方式 - 您可以简单地使用您已经捕获的 HBITMAP。

这是一个加载位图并再次保存的示例。 (我最初使用“image/png”作为输出类型,以及适当的输出文件名)

#include <windows.h>
#include <gdiplus.h>
using namespace Gdiplus;

int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
   UINT  num = 0;          // number of image encoders
   UINT  size = 0;         // size of the image encoder array in bytes

   ImageCodecInfo* pImageCodecInfo = NULL;

   GetImageEncodersSize(&num, &size);
   if(size == 0)
      return -1;  // Failure

   pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
   if(pImageCodecInfo == NULL)
      return -1;  // Failure

   GetImageEncoders(num, size, pImageCodecInfo);

   for(UINT j = 0; j < num; ++j)
   {
      if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
      {
         *pClsid = pImageCodecInfo[j].Clsid;
         free(pImageCodecInfo);
         return j;  // Success
      }
   }
   free(pImageCodecInfo);
   return -1;  // Failure
}

int main()
{
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    HBITMAP hBitmap = (HBITMAP)LoadImage(GetModuleHandle(NULL), "babe.bmp", IMAGE_BITMAP, 0,0, LR_LOADFROMFILE);
    Bitmap *image = new Bitmap(hBitmap, NULL);

    CLSID myClsId;
    int retVal = GetEncoderClsid(L"image/bmp", &myClsId);

    image->Save(L"output.bmp", &myClsId, NULL);
    delete image;

    GdiplusShutdown(gdiplusToken);
    return 0;
}

关于C++:Hbitmap/BITMAP 到 .bmp 文件,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24644709/

10-11 23:07
查看更多