0

im making an application that takes a screenshot of the monitor and then reads it with tesseract. To get better performance id like to avoid saving the screenshot before sending it to tesseract.

I found some example and other related post and came to this code that uses "pixReadMemBm" but it always return a null ptr:

#define _CRT_SECURE_NO_WARNINGS // for strncopy and fopen

#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>


//include leptonica headers
#include <allheaders.h>

//include tesseract headers
#include <baseapi.h>

using namespace std;

TCHAR CurDir[MAX_PATH];
tesseract::TessBaseAPI *api;

void init_tesseract_ocr();
PIX* tesseract_preprocess(PIX* pixs);
string tesseract_ocr(PIX* image);
PIX* ScreenShot(int left, int top, int sizex, int sizey);

int main()
{
    GetCurrentDirectory(MAX_PATH, CurDir);
    init_tesseract_ocr();

    PIX* sc = ScreenShot(0, 0, 500, 30);
    //PIX* pp = tesseract_preprocess(sc);

    //string text = tesseract_ocr(pp);

    //cout << text << endl;

    system("pause");

    return 0;
}



PIX* ScreenShot(int left, int top, int sizex, int sizey)
{
    // get the device context of the screen
    HDC hScreenDC = CreateDC("DISPLAY", NULL, NULL, NULL);

    // and a device context to put it in
    HDC hMemoryDC = CreateCompatibleDC(hScreenDC);


    HBITMAP hBitmap;
    hBitmap = CreateCompatibleBitmap(hScreenDC, sizex, sizey);

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

    BitBlt(hMemoryDC, 0, 0, sizex, sizey, hScreenDC, left, top, SRCCOPY);

    BITMAP bmpScreen;
    GetObject(hBitmap, 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;

    HANDLE hDIB = GlobalAlloc(GHND, dwBmpSize);
    char *lpbitmap = (char *)GlobalLock(hDIB);

    GetDIBits(hScreenDC, hBitmap, 0,
        (UINT)bmpScreen.bmHeight,
        lpbitmap,
        (BITMAPINFO *)&bi, DIB_RGB_COLORS);

    // 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  

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /*HANDLE hFile = CreateFile("UI.bmp",
        GENERIC_WRITE,
        0,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL, NULL);

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

    //Close the handle for the file that was created
    CloseHandle(hFile);*/
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////

    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));
    PIX *mypix = pixReadMemBmp(&buffer[0], buffer.size());

    if (mypix == NULL)
    {
        cout << "mypix is NULL" << endl;
    }
    else
    {
        pixWriteImpliedFormat("preprocess.bmp", mypix, 0, 0);
    }

    DeleteDC(hMemoryDC);
    DeleteDC(hScreenDC);
    DeleteObject(hBitmap);

    GlobalUnlock(hDIB);
    GlobalFree(hDIB);

    /////////////////////////////////////

    return mypix;
}

if I save the screenshot to a file (with the methode commented in the code) i get the expected result, so the problem is those 5 lines:

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));
PIX *mypix = pixReadMemBmp(&buffer[0], buffer.size());

could someone explain to me what i did wrong? Thanks !

  • 1
    If you save the "pixmap" to the file `preprocess.bmp` and the image file is fine, then you know that the copy to memory is working fine (because that's what is saved to the file). So the problem might not be where you think it is, but how you pass on the in-memory image? – Some programmer dude Sep 22 '19 at 10:44
  • It always fall into the "if(mypix==null)" so I dont see how the copying to memory could have been working ? – PappayaPokPok Sep 23 '19 at 06:05
  • Then you don't write anything to the file either, which means you saing "if I save the screenshot to a file i get the expected result" is misleading. Or when you say that, do you mean something *other* that using `pixWriteImpliedFormat` to write to a file? Please edit your question to clarify the details and elaborate. Also please take some time to read about [how to ask good questions](http://stackoverflow.com/help/how-to-ask), as well as [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). – Some programmer dude Sep 23 '19 at 06:12
  • Sorry I should have say then that the code used to write the file to the disk is commented juste above the lines to create the buffer. It does create a file with the expected screenshot. I did not try pixwriteimpliedformat, but it will obviously not work as the pix pointer is null. So the problem is how I create the buffer, those 4 lines before "pixreadmembmp" – PappayaPokPok Sep 23 '19 at 07:34

0 Answers0