38726

Convert a windows BITMAP to a PIX (unsigned char buffer)

Question:

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

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

And this is how I read it:

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

So, I've seen that the library has a PIX * pixReadMemBmp ( const l_uint8 *cdata, size_t size ) <a href="http://search.cpan.org/dist/Image-Leptonica/lib/Image/Leptonica/Func/bmpio.pm#pixReadMemBmp" rel="nofollow">method</a> which takes a l_uint8 which is an unsigned char buffer

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

Answer1:

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

Recommend

  • How to speed up BitBlt to capture screen with aero?
  • ms-access: how to do a proper requery?
  • Win32 GDI Drawing a circle?
  • Copying a bmp in c
  • CustomContent in Primefaces selectOneMenu without persisting object
  • jQuery and Uploadify session in the php file
  • How to get file download speed (transfer rate) with php?
  • How to select table rows/complete table?
  • File loader changed image file name but not the file name in HTML file
  • Is it better to use the “hidden” CSS attribute or fetch each set of new images?
  • MAVEN : Run Multiple Maven Project using Maven Test
  • Responsive left sidebar open close
  • Prevent page break in text block with iText, XMLWorker
  • Get a trait object reference from a vector
  • google maps autocomplete bounces back already cleared text …odd…odd…odd
  • How to unpack 32bit integer packed in a QByteArray?
  • Is there a way to dynamically embed PDF Files in a JSP pulled from the file system?
  • Outputting SharePoint Hyperlink Column as URL
  • C++ friend class std::vector
  • Doctrine/Symfony entity generator and generating entity from one table
  • SyntaxError: (irb):26: both block arg and actual block given
  • Uncaught TypeError: $(…).select2 is not a function
  • How to view images from protected folder with php?
  • Display images in Django
  • copying resource to sdcard gives a damaged file in android
  • Allowing both email and username for authentication
  • Change multiple background-images with jQuery
  • Algorithm for a smudge tool?
  • Get one-time binding to work for ng-if
  • Why is the size of this struct 32?
  • Can Jackson SerializationFeature be overridden per field or class?
  • Resize panoramic image to fixed size
  • Importing jscolor library in angular 2
  • ORA-29908: missing primary invocation for ancillary operator
  • How do you troubleshoot character encoding problems?
  • How to get next/previous record number?
  • Android Studio and gradle
  • How do you join a server to an Active Directory (domain)?
  • How does Linux kernel interrupt the application?
  • Django query for large number of relationships