How to get a string from an hbitmap

Asked

Viewed 180 times

3

I have a function that captures the monitor image and creates a bitmap file with the result, but I would like you to return a string with the content that the file would have, instead of writing it to disk.

The function:

int CaptureRegion(char *filename, int nLeft, int nTop, int nWidth, int nHeight)
{
    HWND hDesktopWnd = GetDesktopWindow(); // Desktop handle
    HDC hDesktopDC = GetDC(hDesktopWnd); // Desktop DC

    BITMAPINFO bi;
    void *pBits = NULL;
    ZeroMemory(&bi, sizeof(bi));
    bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
    bi.bmiHeader.biHeight = nHeight;
    bi.bmiHeader.biWidth = nWidth;
    bi.bmiHeader.biPlanes = 1;
    bi.bmiHeader.biBitCount = 24;
    bi.bmiHeader.biCompression = BI_RGB;
    // bitmap width should be aligned by DWORD under NT
    bi.bmiHeader.biSizeImage = ((nWidth * bi.bmiHeader.biBitCount +31)& ~31) /8 * nHeight; 

    HDC hBmpFileDC=CreateCompatibleDC(hDesktopDC);
    HBITMAP hBmpFileBitmap=CreateDIBSection(hDesktopDC,&bi,DIB_RGB_COLORS,&pBits,NULL,0);
    SelectObject(hBmpFileDC, hBmpFileBitmap);
    BitBlt(hBmpFileDC, 0, 0, nWidth, nHeight, hDesktopDC, nLeft,nTop, SRCCOPY);
        HANDLE  hFile=CreateFile(filename,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
    if(hFile!=INVALID_HANDLE_VALUE)
    {
        DWORD   dwRet = 0;
        BITMAPFILEHEADER bfh;

        ZeroMemory(&bfh, sizeof(bfh));
        bfh.bfType = 0x4D42;
        bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
        bfh.bfSize = bi.bmiHeader.biSizeImage + bfh.bfOffBits;

        WriteFile(hFile, &bfh, sizeof(bfh), &dwRet, NULL);
        WriteFile(hFile, &bi.bmiHeader, sizeof(bi.bmiHeader), &dwRet, NULL);
        WriteFile(hFile, pBits, bi.bmiHeader.biSizeImage, &dwRet, NULL);
        CloseHandle(hFile);
    } else return 0;
    DeleteDC(hBmpFileDC);
    DeleteObject(hBmpFileBitmap);
    ReleaseDC(hDesktopWnd,hDesktopDC);
        return 1;
}

From what I researched, I have to use the function "Getdibits", but I do not know how to proceed.

  • Why do you want to get string from a bit map ? What is the utility?

  • I’m using a library in Lua(luapower/bitmap) that loads the bitmap by the file, but the way I’m using it (taking printscreen every second), I don’t like to keep writing the file on the disk over and over again, since I only use it to look for a pixel and then erase it, to search the next image.

  • If I concatenated the content of bfh, bi.bmiHeader and pBits, it would have the content that the file would have?

  • To you that creating a buffer is not a string.

  • And how do I do that?

  • I don’t know moon I’ll just create the buffer, and DI of GetDIBits means Device-Independent(Standalone Device) if you are going to use bitmap on the same device you do not need to GetDIBits you will need to GetBitmapBits.

  • If you want the bits to search for a pixel do not need all the "formality" of the bitmap format, take only the pixels of the image(pbits) and return.

  • But I need it to be bitmap, for use in Lua, I need it to have the content that the file would have.

Show 3 more comments

1 answer

6


You want the function to return the bitmap data instead of writing it to a file, right? I changed your code a little so that the function returns the data in memory:

unsigned char* CaptureRegion(int nLeft, int nTop, int nWidth, int nHeight, unsigned int* size){
HWND hDesktopWnd = GetDesktopWindow(); // Desktop handle
HDC hDesktopDC = GetDC(hDesktopWnd); // Desktop DC
unsigned char* image;

BITMAPINFO bi;
void *pBits = NULL;
ZeroMemory(&bi, sizeof(bi));
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biHeight = nHeight;
bi.bmiHeader.biWidth = nWidth;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 24;
bi.bmiHeader.biCompression = BI_RGB;
// bitmap width should be aligned by DWORD under NT
bi.bmiHeader.biSizeImage = ((nWidth * bi.bmiHeader.biBitCount + 31)& ~31) / 8 * nHeight;

HDC hBmpFileDC = CreateCompatibleDC(hDesktopDC);
HBITMAP hBmpFileBitmap = CreateDIBSection(hDesktopDC, &bi, DIB_RGB_COLORS, &pBits, NULL, 0);
SelectObject(hBmpFileDC, hBmpFileBitmap);
BitBlt(hBmpFileDC, 0, 0, nWidth, nHeight, hDesktopDC, nLeft, nTop, SRCCOPY);

DWORD   dwRet = 0;
BITMAPFILEHEADER bfh;

ZeroMemory(&bfh, sizeof(bfh));
bfh.bfType = 0x4D42;
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bfh.bfSize = bi.bmiHeader.biSizeImage + bfh.bfOffBits;

*size = sizeof(bfh) + sizeof(bi.bmiHeader) + bi.bmiHeader.biSizeImage;
image = new unsigned char[*size];

memcpy_s(image, sizeof(bfh), &bfh, sizeof(bfh));
memcpy_s(image + sizeof(bfh), sizeof(bi.bmiHeader), &bi.bmiHeader, sizeof(bi.bmiHeader));
memcpy_s(image + sizeof(bfh) + sizeof(bi.bmiHeader), bi.bmiHeader.biSizeImage, pBits, bi.bmiHeader.biSizeImage);

DeleteDC(hBmpFileDC);
DeleteObject(hBmpFileBitmap);
ReleaseDC(hDesktopWnd, hDesktopDC);

return (unsigned char*)image;
}

Instead of writing to a file you allocate sufficient memory pro bitmap, copy the content to it and return the data. If you want you can still write them in a file:

unsigned char* image = CaptureRegion(0, 0, 500, 500, &size);

std::ofstream file("desktop.bmp", std::ios_base::out |std::ios_base::binary);

if (!file.is_open()) {
    std::cout << "Failed to open file!\n";
    delete [] image;
    return 0;
}

file.write((char*)image, size);
file.close();
delete[] image;

Obs: I also recommend checking errors with these windows functions :

  • I did a test, but only returned "BM60". Just the header, I think there is something wrong in the parameters of memcpy_s function, I’ll see if I find out. That’s a big step up.

  • It worked as it should, thank you

  • memcpy_s is windows thing, it asks only one more parameter that is the size available in the target buffer. What was wrong?

  • It was human error(mine), your code is good. kk

  • I am using the function, to write a file, works well, but when I use the command sizeof in the amount that Captureregion returns, always get 4 and I can only use that value to write a file, nothing more.

  • The value returned is a pointer, pointers have 4 bytes so sizeof returns 4, look right the code that writes the image in the file, I use the variable size to get the image size.

  • Right, there’s how I "copy" the entire value to a const char*? Not only (const char)image*, because they return only 4 bits, but all the value.

  • yes, you can use memcpy_s or even make a loop: for(unsigned int i = 0; i < size; i++)...

  • Using your code, I made this program: [link] http://pastebin.com/FZaNxPAR , it writes the file correctly, but the output is not expected, the same happens when I try to pass the value to the Moon, you know why it can be?

  • The output is correct, you who programmed wrong, the variable imagem returned by the two functions is nothing more than a memory address, the std::cout understand this(const char*) as a string and will print the data until you find a \0, that coincidentally is right after the bmp identifier, only that the data is not a string, it is an image and it doesn’t make much sense (in most cases) to try to print it as a string. The proof of the fix is that the image file was generated correctly! about its moon function you are probably also using it incorrectly.

  • I recommend these links: https://www.ime.usp.br/~pf/algoritmos/aulas/Pont.html http://www.inf.pucrs.br/~pinho/PRGSWB/pointers.html

  • I tried (*image), but it’s still the same, it can shed more light?

Show 8 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.