Taking a JPEG-encoded screenshot into a buffer using GDI + and C ++

I adjusted this code from another article here on SO . It takes a screenshot of the desktop and writes it to a file called "test.jpg."

I am interested in saving JPEG data directly to a buffer that will be sent over the network. I am pretty sure that GdipSaveImageToStream is what I need, but I can't figure out how it works. The GpImage parameter GpImage particularly confusing.

I appreciate any help you can provide.

 #include "stdafx.h" #include "windows.h" #include "gdiplus.h" using namespace Gdiplus; using namespace Gdiplus::DllExports; int GetEncoderClsid(WCHAR *format, CLSID *pClsid) { unsigned int num = 0, size = 0; GetImageEncodersSize(&num, &size); if(size == 0) return -1; ImageCodecInfo *pImageCodecInfo = (ImageCodecInfo *)(malloc(size)); if(pImageCodecInfo == NULL) return -1; GetImageEncoders(num, size, pImageCodecInfo); for(unsigned int j = 0; j < num; ++j) { if(wcscmp(pImageCodecInfo[j].MimeType, format) == 0){ *pClsid = pImageCodecInfo[j].Clsid; free(pImageCodecInfo); return j; } } free(pImageCodecInfo); return -1; } int GetScreeny(LPWSTR lpszFilename, ULONG uQuality) // by Napalm { ULONG_PTR gdiplusToken; GdiplusStartupInput gdiplusStartupInput; GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); HWND hMyWnd = GetDesktopWindow(); // get my own window RECT r; // the area we are going to capture int w, h; // the width and height of the area HDC dc; // the container for the area int nBPP; HDC hdcCapture; LPBYTE lpCapture; int nCapture; int iRes; CLSID imageCLSID; Bitmap *pScreenShot; HGLOBAL hMem; int result; // get the area of my application window //GetClientRect(hMyWnd, &r); GetWindowRect(hMyWnd, &r); dc = GetWindowDC(hMyWnd);// GetDC(hMyWnd) ; w = r.right - r.left; h = r.bottom - r.top; nBPP = GetDeviceCaps(dc, BITSPIXEL); hdcCapture = CreateCompatibleDC(dc); // create the buffer for the screenshot BITMAPINFO bmiCapture = { sizeof(BITMAPINFOHEADER), w, -h, 1, nBPP, BI_RGB, 0, 0, 0, 0, 0, }; // create a container and take the screenshot HBITMAP hbmCapture = CreateDIBSection(dc, &bmiCapture, DIB_PAL_COLORS, (LPVOID *)&lpCapture, NULL, 0); // failed to take it if(!hbmCapture) { DeleteDC(hdcCapture); DeleteDC(dc); GdiplusShutdown(gdiplusToken); printf("failed to take the screenshot. err: %d\n", GetLastError()); return 0; } // copy the screenshot buffer nCapture = SaveDC(hdcCapture); SelectObject(hdcCapture, hbmCapture); BitBlt(hdcCapture, 0, 0, w, h, dc, 0, 0, SRCCOPY); RestoreDC(hdcCapture, nCapture); DeleteDC(hdcCapture); DeleteDC(dc); GpImage *bob; IStream *ssStr; // save the buffer to a file pScreenShot = new Bitmap(hbmCapture, (HPALETTE)NULL); EncoderParameters encoderParams; encoderParams.Count = 1; encoderParams.Parameter[0].NumberOfValues = 1; encoderParams.Parameter[0].Guid = EncoderQuality; encoderParams.Parameter[0].Type = EncoderParameterValueTypeLong; encoderParams.Parameter[0].Value = &uQuality; GetEncoderClsid(L"image/jpeg", &imageCLSID); iRes = (pScreenShot->Save(lpszFilename, &imageCLSID, &encoderParams) == Ok); delete pScreenShot; DeleteObject(hbmCapture); GdiplusShutdown(gdiplusToken); return iRes; } int _tmain(int argc, _TCHAR* argv[]) { GetScreeny(L"test.jpg", 75); return 0; } 
+6
source share
1 answer

Short answer: use the version of Gdiplus ISitream :: Image :: Save. Use CreateHStreamOnGlobal to make a temporary IStream that you can convert back to a buffer;

Long-term version with sample code.

Replace this line:

  iRes = (pScreenShot->Save(lpszFilename, &imageCLSID, &encoderParams) == Ok); 

With this code block:

 // Note: For the sake of brevity and readability, I'm deliberately not checking // the return value of any of these calls. In production code, you should do diligent error // checking on each function call. Also, there may be an optimization where you can just // use the memory of the stream itself (by calling GetHGlobalFromStream and GlobalLock) // But that an exercise left to the reader. { IStream *pStream = NULL; LARGE_INTEGER liZero = {}; ULARGE_INTEGER pos = {}; STATSTG stg = {}; ULONG bytesRead=0; HRESULT hrRet=S_OK; BYTE* buffer = NULL; // this is your buffer that will hold the jpeg bytes DWORD dwBufferSize = 0; // this is the size of that buffer; hrRet = CreateStreamOnHGlobal(NULL, TRUE, &pStream)) hrRet = pScreenShot->Save(pStream, &imageCLSID, &encoderParams) == 0 ? S_OK : E_FAIL; hrRet = pStream->Seek(liZero, STREAM_SEEK_SET, &pos); hrRet = pStream->Stat(&stg, STATFLAG_NONAME); // allocate a byte buffer big enough to hold the jpeg stream in memory buffer = new BYTE[stg.cbSize.LowPart]; hrRet = (buffer == NULL) ? E_OUTOFMEMORY : S_OK; dwBufferSize = stg.cbSize.LowPart; // copy the stream into memory hrRet = pStream->Read(buffer, stg.cbSize.LowPart, &bytesRead); // now go save "buffer" and "dwBufferSize" off somewhere. This is the jpeg buffer // don't forget to free it when you are done // After success or if any of the above calls fail, don't forget to release the stream if (pStream) { pStream->Release(); } } 
+7
source

Source: https://habr.com/ru/post/885596/


All Articles