How to capture part of the screen and save it to a BMP? [duplicate]
Asked Answered
W

2

10

Possible Duplicate:
how to make screen screenshot with win32 in c++?

I am currently trying to create an application that saved a portion of the screen to a bmp. I have found BitBlt but I really don't know what to do with it. I have tried searching for some answers but I still haven't found a clarifying one using C++.

So, basically I want this function:

bool capturePartScreen(int x, int y, int w int, h, string dest){
    //Capture part of screen according to coordinates, width and height.
    //Save that captured image as a bmp to dest.
    //Return true if success, false if failure
}

BitBlt:

BOOL BitBlt(
    __in  HDC hdcDest,
    __in  int nXDest,
    __in  int nYDest,
    //The three above are the ones I don't understand!
    __in  int nWidth,
    __in  int nHeight,
    __in  HDC hdcSrc,
    __in  int nXSrc,
    __in  int nYSrc,
    __in  DWORD dwRop
);

What should that hdc be and how do I obtain the bmp?

Windywindzer answered 1/3, 2012 at 21:28 Comment(6)
Look at this SO question.Dare
Check out this question, it should point you in the right directionSedda
@Jesse: Thanks, that post helped me out quite a bit :)Windywindzer
Not an exact duplicate, since a key part of the question is how to get the bitmap into a file. The other question does not address that at all.Nucleate
Indeed.. Well, at least I managed to post an answer before it was closed :/Windywindzer
This is not a duplicate at all - aside from the file saving, this question asks about capturing part of a screen whereas the linked question asks about capturing the entire screen. Trigger-happy question closing is annoying.Gyrostatic
W
21

It took a while, but I have now finally ended up with a functioning script.

Requirements:

#include <iostream>
#include <ole2.h>
#include <olectl.h>

Also you might(?) have to add ole32, oleaut32 and uuid to your linker.

screenCapturePart:

bool screenCapturePart(int x, int y, int w, int h, LPCSTR fname){
    HDC hdcSource = GetDC(NULL);
    HDC hdcMemory = CreateCompatibleDC(hdcSource);

    int capX = GetDeviceCaps(hdcSource, HORZRES);
    int capY = GetDeviceCaps(hdcSource, VERTRES);

    HBITMAP hBitmap = CreateCompatibleBitmap(hdcSource, w, h);
    HBITMAP hBitmapOld = (HBITMAP)SelectObject(hdcMemory, hBitmap);

    BitBlt(hdcMemory, 0, 0, w, h, hdcSource, x, y, SRCCOPY);
    hBitmap = (HBITMAP)SelectObject(hdcMemory, hBitmapOld);

    DeleteDC(hdcSource);
    DeleteDC(hdcMemory);

    HPALETTE hpal = NULL;
    if(saveBitmap(fname, hBitmap, hpal)) return true;
    return false;
}

saveBitmap:

bool saveBitmap(LPCSTR filename, HBITMAP bmp, HPALETTE pal)
{
    bool result = false;
    PICTDESC pd;

    pd.cbSizeofstruct   = sizeof(PICTDESC);
    pd.picType      = PICTYPE_BITMAP;
    pd.bmp.hbitmap  = bmp;
    pd.bmp.hpal     = pal;

    LPPICTURE picture;
    HRESULT res = OleCreatePictureIndirect(&pd, IID_IPicture, false,
                       reinterpret_cast<void**>(&picture));

    if (!SUCCEEDED(res))
    return false;

    LPSTREAM stream;
    res = CreateStreamOnHGlobal(0, true, &stream);

    if (!SUCCEEDED(res))
    {
    picture->Release();
    return false;
    }

    LONG bytes_streamed;
    res = picture->SaveAsFile(stream, true, &bytes_streamed);

    HANDLE file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, 0,
                 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

    if (!SUCCEEDED(res) || !file)
    {
    stream->Release();
    picture->Release();
    return false;
    }

    HGLOBAL mem = 0;
    GetHGlobalFromStream(stream, &mem);
    LPVOID data = GlobalLock(mem);

    DWORD bytes_written;

    result   = !!WriteFile(file, data, bytes_streamed, &bytes_written, 0);
    result  &= (bytes_written == static_cast<DWORD>(bytes_streamed));

    GlobalUnlock(mem);
    CloseHandle(file);

    stream->Release();
    picture->Release();

    return result;
}
Windywindzer answered 1/3, 2012 at 23:24 Comment(4)
For those getting E_UNEXPECTED after OleCreatePictureIndirect, I forgot to set PICTDESC.picType to PICTYPE_BMP.Touchwood
Just a note for future readers... In that first code block screenCapturePart the bit that reads BitBlt(hdcMemory, 0, 0, w, h, hdcSource, x, x, SRCCOPY); should actually be BitBlt(hdcMemory, 0, 0, w, h, hdcSource, x, y, SRCCOPY);.Antimony
@ChrisBarlow Fixed, thanks for noticing and telling!Windywindzer
Thanks a lot! I SO did not want to figure that out for myself. One note, I was getting cannot convert argument from 'LPCSTR' to 'LPCWSTR' which I fixed by using CreateFileA instead of CreateFile.Diazonium
J
3

You can use GetDC(NULL) to get the device context for the entire screen, then use that with BitBlt as the source device context.

As for the rest of what to do:

Bitmap Creation (Windows)

Bitmap Storage (Windows)

Juliannejuliano answered 1/3, 2012 at 21:33 Comment(1)
Yes I know, but what I don't understand is how to define the destination hdc. How do I go from a hdc to a bmp? Sorry for not clarifying that.Windywindzer

© 2022 - 2024 — McMap. All rights reserved.