通过C ++和C#应用程序之间的套接字进行图像传输

时间:2015-11-16 16:02:08

标签: c# c++ sockets bitmap

我在C ++中使用服务器应用程序制作屏幕截图,必须将其传输到用C#编写的客户端。我遇到了一些问题:

  1. 我不能转移bmp图片,因为它太重了,所以我需要将图像转换为另一种格式(jpg,png也许?)
  2. 我需要在客户端检索图片的字节数组,并将其用作图片框的图片。
  3. 问题在于我不知道实现这一目标的正确算法。将图像保存到服务器端的文件并传输文件然后将文件保存在客户端上,然后将其读取到图片框也不是解决方案。因此,总结我的任务:如何将位图转换为轻量级格式并将其传输到客户端?

    感谢您的时间!

3 个答案:

答案 0 :(得分:2)

如果您可以使用c ++应用程序中的.Net托管代码,那么您可以使用本机库(请参阅https://stackoverflow.com/a/3517974/149818)。

如果您仅受明确的c ++限制,请参阅LodePNG

答案 1 :(得分:1)

您可以在c ++端使用libpng转换为.png。 在C#端,Bitmap类.png可以通过以下方式加载:

new Bitmap(png);

请记住:我对C#方面可能不对。

答案 2 :(得分:0)

非常感谢回答这个问题!经过对堆栈的一些研究后,我发现了类似的问题,并且有一个代码可以将jpg图像转换为可以通过套接字传输的字节数组。这是(某些变量可能未使用)

#include <objidl.h>
#include <Gdiplus.h>
#pragma comment(lib, "gdiplus.lib")

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

BYTE *GetScreeny(LPWSTR lpszFilename, ULONG uQuality, int *buff_size) // 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);

    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
    BYTE *buffer = new BYTE[stg.cbSize.LowPart];
    //buffer = (BYTE *)malloc(stg.cbSize.LowPart);
    hrRet = (buffer == NULL) ? E_OUTOFMEMORY : S_OK;
    dwBufferSize = stg.cbSize.LowPart;
    //wchar_t message[512];
    //wsprintf(message, L"%d", stg.cbSize.LowPart);
    //MessageBox(NULL, message, NULL, MB_OK);
    // 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();
    }

    delete pScreenShot;
    DeleteObject(hbmCapture);
    GdiplusShutdown(gdiplusToken);
    *buff_size = (int)dwBufferSize;
    //return iRes;
    return buffer;

}