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 GlobalAlloc 转换为全局可访问的句柄,该句柄可以转换或与 LPBITMAPINFOHEADER 一起使用。
创建 lpbi 后,其中的每个字段都是 Visual Studio 2012 调试中的“无法读取内存”错误。尽管已创建,但它无法访问。
解决方案..
直接从 screencap 到 PIX,在内存中..
找到一种方法来保存到位图并定期创建它们以读取..
找到另一种更有意义的方式。
更喜欢第一个,但是,我在寻求解决方案,而不是第二个……或第三个。
如果您需要更多信息,我可以尝试提供。这主要归结为“我以前从未编写过这样的代码,而且我的类(class)中没有教过它,所以我正在努力学习”。
(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/