【问题标题】:How do I write out a screen shot to a PNG?如何将屏幕截图写入 PNG?
【发布时间】:2018-02-18 04:01:20
【问题描述】:

我在网上找到了这段代码来打印屏幕(截图),但我不知道如何修改它以将结果保存为 PNG 文件。

我可以将位图保存到剪贴板,但我现在需要保存到 PNG 文件。

  • 是否可以从剪贴板中提取位图并将其保存为 PNG 文件?
  • 这可以做不同的吗?
  • 如果是,怎么做?

到目前为止我的代码是:

#include <iostream>
#include <windows.h>
#include <gdiplus.h>
#include <stdexcept>

 using namespace std;
 using namespace Gdiplus;
 using namespace Gdiplus::DllExports;
 using std::runtime_error;

void screenshot(POINT a, POINT b)
{

    HDC     hScreen = GetDC(NULL);
    HDC     hDc     = CreateCompatibleDC(hScreen);
    HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, abs(b.x-a.x), abs(b.y-a.y));
    HGDIOBJ old_obj = SelectObject(hDc, hBitmap);
    BOOL    bRet    =  BitBlt(hDc, 0, 0, abs(b.x-a.y), abs(b.y-a.y), hScreen, a.x, a.y, SRCCOPY);

    OpenClipboard(NULL);
    EmptyClipboard();
    SetClipboardData(CF_BITMAP, hBitmap);
    CloseClipboard();


    SelectObject(hDc, old_obj);
    DeleteDC(hDc);
    ReleaseDC(NULL, hScreen);
    DeleteObject(hBitmap);
}

int main()
{
    POINT a,b;
    a.x=386;
    a.y=749;

    b.x=686;
    b.y=1049;

    screenshot(a,b);
}

链接 - https://causeyourestuck.io/2016/01/12/screenshot-c-win32-api/ 作者奥马尔 AFLAK

【问题讨论】:

  • ... 您可以停止重复您想要将内容保存到 PNG 文件并需要帮助。你现在肯定已经说了十遍了,再说一遍不会让你的问题更精确!
  • 我重新打开了这个问题,因为它比原始版本大大改进了,但是您仍然需要提供attribution 以获取您在“在网”。网站链接和作者姓名是最低要求。
  • 至于你的问题的答案,你可以找到它here,虽然这个问题并不是这个问题的重复。如果您为 PNG 文件提供适当的编码器类 ID,GDI+ 可以直接将其写入。另见:stackoverflow.com/questions/5345803/…

标签: c++ windows bitmap png gdi+


【解决方案1】:

首先,包含 Gdiplus 的库。在 Visual Studio 中,您可以使用 #pragam 关键字或在项目设置中添加 Gdiplus.lib。

接下来,用Gdiplus::GdiplusStartup初始化Gdiplus

找到前面提到的编码器CLSID

在你的代码中有abs(b.x-a.y),大概应该是abs(b.x-a.x)。如果a 应该是起点,则此逻辑可能不起作用。只要确保POINT b 大于POINT a。或者仔细阅读BitBlt的文档

#include <Windows.h>
#include "gdiplus.h"

//Visual Studio shortcut for adding library:
#pragma comment(lib, "Gdiplus.lib")

int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
    UINT  num = 0;          // number of image encoders
    UINT  size = 0;         // size of the image encoder array in bytes

    Gdiplus::GetImageEncodersSize(&num, &size);
    if(size == 0)
        return -1;  // Failure

    Gdiplus::ImageCodecInfo* pImageCodecInfo = (Gdiplus::ImageCodecInfo*)(malloc(size));
    if(pImageCodecInfo == NULL)
        return -1;  // Failure

    GetImageEncoders(num, size, pImageCodecInfo);

    for(UINT j = 0; j < num; ++j)
    {
        if(wcscmp(pImageCodecInfo[j].MimeType, format) == 0)
        {
            *pClsid = pImageCodecInfo[j].Clsid;
            free(pImageCodecInfo);
            return j;  // Success
        }
    }

    free(pImageCodecInfo);
    return -1;  // Failure
}

void screenshot(POINT a, POINT b)
{
    int w = b.x - a.x;
    int h = b.y - a.y;

    if(w <= 0) return;
    if(h <= 0) return;

    HDC     hScreen = GetDC(HWND_DESKTOP);
    HDC     hDc = CreateCompatibleDC(hScreen);
    HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, w, h);
    HGDIOBJ old_obj = SelectObject(hDc, hBitmap);
    BitBlt(hDc, 0, 0, w, h, hScreen, a.x, a.y, SRCCOPY);

    Gdiplus::Bitmap bitmap(hBitmap, NULL);
    CLSID clsid;

    GetEncoderClsid(L"image/png", &clsid);

    //GDI+ expects Unicode filenames
    bitmap.Save(L"c:\\test\\test.png", &clsid);

    SelectObject(hDc, old_obj);
    DeleteDC(hDc);
    ReleaseDC(HWND_DESKTOP, hScreen);
    DeleteObject(hBitmap);
}

int main()
{
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    RECT      rc;
    GetClientRect(GetDesktopWindow(), &rc);
    POINT a{ 0, 0 };
    POINT b{ 100, 100 };

    screenshot(a, b);

    Gdiplus::GdiplusShutdown(gdiplusToken);

    return 0;
}

【讨论】:

  • throws me c2731 'winmain' 函数无法重载。如何解决?
  • 您之前在代码中显示了main 入口点。如果您将mainwWinMainWinMain 混合使用,则会出现错误。 GDI+ 函数需要 Unicode 输入/输出进行文本传输。
  • @F.Fipoo 正如 Barmak Shemirani 所暗示的那样,如果使用 Visual Studio,您需要转到您的项目设置并将 General-&gt;Project Defaults-&gt;Character set 更改为 Use Unicode Character Set,这应该不会破坏编译。默认为Use Multi-Byte Character Set
  • @kayleeFrye_onDeck 我刚刚更改为 main,因为 wmain 是 Visual Studio 特定的。
  • bitmap.Save(L"c:\\test\\test.png", &amp;clsid, NULL); 为 mingw。
猜你喜欢
  • 2013-10-10
  • 1970-01-01
  • 2012-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多