2011-04-10 1 views
6

이 코드를 another article here on SO에서 수정했습니다. 바탕 화면의 스크린 샷을 찍은 다음 "test.jpg"라는 파일에 씁니다.GDI + 및 C++를 사용하여 JPEG로 인코딩 된 스크린 샷을 버퍼에 저장

네트워크를 통해 전송할 버퍼에 JPEG 데이터를 직접 저장하는 데 관심이 있습니다. 나는 꽤 확신하고있다. GdipSaveImageToStream은 내가 필요로하는 것이지만 그것이 어떻게 작동하는지 알 수 없다. GpImage 매개 변수가 특히 혼란 스럽습니다.

제공할만한 도움에 감사드립니다.

#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's 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; 
} 

답변

7

짧은 대답 : IStream 버전의 Gdiplus :: Image :: Save를 사용하십시오. CreateHStreamOnGlobal을 사용하여 버퍼로 다시 변환 할 수있는 임시 IStream을 만듭니다.

코드 샘플이 포함 된 장황한 버전입니다. 코드 블록으로

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

:

// 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's 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(); 
    } 
} 
+0

감사합니다

이 라인을 교체! 그것은 훌륭하게 작동합니다. – Smurf64

+1

@ Smurf64 서버 측에 버퍼 데이터를 보낸 후 원본 이미지로 가져온 방법 – Ganesh

관련 문제