【问题标题】:How to capture part of the screen and save it to a BMP? [duplicate]如何捕获部分屏幕并将其保存到 BMP? [复制]
【发布时间】:2012-03-20 10:20:12
【问题描述】:

可能重复:
how to make screen screenshot with win32 in c++?

我目前正在尝试创建一个将屏幕的一部分保存到 bmp 的应用程序。我找到了BitBlt,但我真的不知道如何处理它。我已经尝试寻找一些答案,但我仍然没有找到使用 C++ 的澄清答案。

所以,基本上我想要这个功能:

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

那个hdc应该是什么,我如何获得bmp?

【问题讨论】:

  • 看看这个SO question
  • 看看这个question,它应该会为你指明正确的方向
  • @Jesse:谢谢,那篇文章对我帮助很大:)
  • 不是完全重复的,因为问题的关键部分是如何将位图放入文件中。另一个问题根本没有解决这个问题。
  • 这根本不是重复的——除了文件保存之外,这个问题询问捕获屏幕的部分,而链接的问题询问捕获整个 屏幕。触发愉快的问题结束很烦人。

标签: c++ winapi bmp screen-capture


【解决方案1】:

花了一段时间,但我现在终于有了一个正常运行的脚本。

要求:

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

您还可能(?)必须将 ole32、oleaut32 和 uuid 添加到您的链接器中。

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

保存位图:

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

【讨论】:

  • 对于那些在 OleCreatePictureIndirect 之后获得 E_UNEXPECTED 的人,我忘记将 PICTDESC.picType 设置为 PICTYPE_BMP。
  • 只是给未来读者的一个注释......在第一个代码块screenCapturePart 中读取BitBlt(hdcMemory, 0, 0, w, h, hdcSource, x, x, SRCCOPY); 的位实际上应该是BitBlt(hdcMemory, 0, 0, w, h, hdcSource, x, y, SRCCOPY);
  • @ChrisBarlow 已修复,感谢您的关注和告知!
  • 非常感谢!我不想为自己解决这个问题。请注意,我得到了cannot convert argument from 'LPCSTR' to 'LPCWSTR',我通过使用CreateFileA而不是CreateFile来修复它。
【解决方案2】:

您可以使用GetDC(NULL) 获取整个屏幕的设备上下文,然后将其与BitBlt 一起用作源设备上下文。

至于剩下的怎么办:

Bitmap Creation (Windows)

Bitmap Storage (Windows)

【讨论】:

  • 是的,我知道,但我不明白如何定义目标 hdc。我如何从 hdc 转到 bmp?很抱歉没有澄清这一点。
猜你喜欢
  • 1970-01-01
  • 2015-12-18
  • 1970-01-01
  • 2013-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-02
  • 2016-02-13
相关资源
最近更新 更多