将Windows BITMAP转换为PIX(无符号字符缓冲区) [英] Convert a windows BITMAP to a PIX (unsigned char buffer)

查看:145
本文介绍了将Windows BITMAP转换为PIX(无符号字符缓冲区)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在截取窗口的屏幕截图,以便使用Leptonica进行处理,然后使用Tesseract

I'm taking a screenshot of a window in order to proccess it with Leptonica and later do some OCR with Tesseract

问题是,从性能角度考虑,我想避免将BMP写入和读取光盘,而只是在内存中工作.这就是我制作屏幕截图的方式:

The problem is, performance wise I would like to avoid writing and reading the BMP to the disc and just work in memory instead. This is how I make the screenshot:

int width, height = 0;

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(hWnd);

hdcWindow = GetDC(hWnd);

// Create a compatible DC which is used in a BitBlt from the window DC
hdcMemDC = CreateCompatibleDC(hdcWindow);

if (!hdcMemDC)
{
    MessageBox(hWnd, L"CreateCompatibleDC has failed", L"Failed", MB_OK);
    goto done;
}

// Get the client area for size calculation
RECT rcClient;
GetClientRect(hWnd, &rcClient);


// Create a compatible bitmap from the Window DC
hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);

if (!hbmScreen)
{
    MessageBox(hWnd, L"CreateCompatibleBitmap Failed", L"Failed", MB_OK);
    goto done;
}

// Select the compatible bitmap into the compatible memory DC.
SelectObject(hdcMemDC, hbmScreen);

// Bit block transfer into our compatible memory DC.
if (!BitBlt(hdcMemDC,
    0, 0,
    rcClient.right - rcClient.left, rcClient.bottom - rcClient.top,
    hdcWindow,
    0, 0,
    SRCCOPY))
{
    MessageBox(hWnd, L"BitBlt has failed", L"Failed", MB_OK);
    goto done;
}

// Get the BITMAP from the HBITMAP
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"pics/UI.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);

width = rcClient.right - rcClient.left;
height = rcClient.bottom - rcClient.top;

//Clean up
done:
DeleteObject(hbmScreen);
DeleteObject(hdcMemDC);
ReleaseDC(hWnd, hdcWindow);

这就是我的阅读方式:

PIX* pixUI = pixRead("pics/UI.bmp");

因此,我已经看到该库具有PIX * pixReadMemBmp ( const l_uint8 *cdata, size_t size )

So, I've seen that the library has a PIX * pixReadMemBmp ( const l_uint8 *cdata, size_t size ) method which takes a l_uint8 which is an unsigned char buffer

问题是,我不明白如何从HBITMAPBITMAP对象中获得这样的缓冲区.

The problem is, I don't understand how I can get such a buffer from my HBITMAP or BITMAP object.

推荐答案

首先将位图复制到缓冲区中,然后将该缓冲区移到pixReadMemBmp()中.复制是必须完成的,因为我假设pixReadMemBmp()函数需要位图数据前面的两个位图标头,就像在文件中一样.伪代码:

Copy the bitmap into a buffer first, then hand this buffer to pixReadMemBmp(). The copying has to be done because , I assume, the pixReadMemBmp() function needs the both bitmap headers in front of the bitmap data, as it would be in a file. Pseudocode:

std::vector<unsigned char> buffer(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwBmpSize);
std::copy(reinterpret_cast<unsigned char*>(&bmfHeader), reinterpret_cast<unsigned char*>(&bmfHeader) + sizeof(BITMAPFILEHEADER), buffer.begin());
std::copy(reinterpret_cast<unsigned char*>(&bi), reinterpret_cast<unsigned char*>(&bi) + sizeof(BITMAPINFOHEADER), buffer.begin() + sizeof(BITMAPFILEHEADER));
std::copy(lpbitmap, lpbitmap + dwBmpSize, buffer.begin() + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));
pixReadMemBmp(&buffer[0], buffer.size());

这篇关于将Windows BITMAP转换为PIX(无符号字符缓冲区)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆