2017-09-09 30 views
-1

我在网上找到这个代码来打印屏幕(截图),但我不知道如何修改它以将结果保存到PNG文件。如何写出一个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

+0

的文件...您可以停止重复你想要的东西保存到一个PNG文件,并希望与帮助。你一定已经说过十次了,再说一次也不会让你的问题更加准确! –

+0

我重新提出这个问题是因为它的*性能比原来的版本有了很大的提高,但是您仍然需要提供[attribution](https://stackoverflow.com/help/referencing)来获取您找到的代码的来源“on网络“。链接到网站和作者的名字是最低要求。 –

+1

至于你的问题的答案,你可以找到它[这里](https://stackoverflow.com/questions/39551863/creating-gdi-bitmaps-in-memory-and-then-saving-as-png) ,尽管这个问题并不是这个问题的重复。如果您提供相应的编码器类ID,GDI +可以直接写出PNG文件。另请参阅:https://stackoverflow.com/questions/5345803/does-gdi-have-standard-image-encoder-clsids –

回答

0

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

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

查找在前面提到的编码器CLSID

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

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

#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); 
    bitmap.Save(L"c:\\test\\test.png", &clsid); 

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

int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPTSTR, int) 
{ 
    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; 
} 
+0

抛出c2731'winmain'函数不能重载。如何解决它? –

+0

您之前在代码中显示了'main'入口点。如果你将'main'与'wWinMain'或'WinMain'混合使用,你会得到一个错误。 GDI +功能需要Unicode输入/输出用于文本传输。 –