1

I'd like to take a PNG formatted screen shot.
But I have a serious problem which I thought that it seems to easy for professor.
1. How can I get image buffer from Bitmap (Class).
2. I am using multi-display, also different resolutions. How can I get a full screen resolution.

Implementation:

#pragma comment (lib, "gdiplus.lib")
#include "stdafx.h"
#include <afxwin.h>
#include <stdio.h>
#include <tchar.h>
#include <gdiplus.h>
using namespace Gdiplus;

DWORD PNGScreenshot();
INT GetEncoderClsid(const WCHAR * format, CLSID* pClsid);

INT GetEncoderClsid(const WCHAR * format, CLSID* pClsid)
{
    UINT num = 0;
    UINT size = 0;
    ImageCodecInfo* pImageCodecInfo = NULL;

    GetImageEncodersSize(&num, &size);
    if (size == 0)
        return -1;
    pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
    if (pImageCodecInfo == NULL)
        return -1;

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

    free(pImageCodecInfo);
    return -1;
}
DWORD PNGScreenshot()
{
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    HDC hScreenDC = CreateDC(L"DISPLAY", NULL, NULL, NULL);
    HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
    INT x = GetDeviceCaps(hScreenDC, HORZRES);
    INT y = GetDeviceCaps(hScreenDC, VERTRES);

    HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, x, y);
    HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, hBitmap);

    StretchBlt(hMemoryDC, 0, 0, x, y, hScreenDC, 0, 0, x, y, SRCCOPY);
    hBitmap = (HBITMAP)SelectObject(hMemoryDC, hOldBitmap);

    CLSID pngClsid;
    GetEncoderClsid(L"image/png", &pngClsid);

    Bitmap *bmp = new Bitmap(hBitmap, NULL);
    // Get Image Buffer from Bitmap
    // GetBufferFromBitmap(LPBYTE lpImageBuffer, Bitmap * bmp);
    // {
    //      1. Get Size of Bitmap
    //      2. Get Image buffer from Bitmap
    //      3. Copy Image buffer to lpImageBuffer
    // }
    // ... Do ...

    delete bmp;

    GdiplusShutdown(gdiplusToken);

    return GetLastError();
}

int _tmain(int argc, _TCHAR* argv[])
{
    PNGScreenshot();

    return 0;
}

This is only my implementation, then is there any other way to get a PNG screen shot as a buffer?

AleXelton
  • 767
  • 5
  • 27
  • I used `INT x = GetSystemMetrics(SM_XVIRTUALSCREEN);` `INT y = GetSystemMetrics(SM_YVIRTUALSCREEN);` But same problem occurred. – AleXelton Dec 05 '19 at 09:42

1 Answers1

0

An alternative implementation might be to use the IStream interface.
Use the Save method to store the bitmap to an IStream object with the clsid_png codec and then back to Image FromStream. @Barmak's MCVE uses memcpy instead of FromStream.

Laurie Stearn
  • 959
  • 1
  • 13
  • 34