[MFC/C++]通过套接字发送CBitmap的位,并在接收器端重建它

[MFC/C++]Sending CBitmap's bits over socket, and re-construct it on receiver side

本文关键字:的位 接收器 重建 CBitmap C++ MFC 套接字      更新时间:2023-10-16

我是MFC的新手,并试图通过基于VS2008的MFC对话框项目来学习它。以下是我所做的归档:

首先,我已经设法将文件夹中的图片列表显示到Listbox控件中。之后,我还处理了列表框每一行上的单击事件,以加载图片并将其显示给右侧的图片控件(类型为位图)。您可以看到下面的图像以便于理解:请单击此处查看我的MFC对话框的图像

这是代码。注意m_ListCtrlstatic_picture是列表框和图片控件的变量:

void CMyClientDlg::OnLbnSelchangeList1(){
CString imagePath;
m_ListCtrl.GetText(m_ListCtrl.GetCurSel(),imagePath);
CImage picture;
picture.Load(imagePath);
if (!picture.IsNull())
{
    float screenWidth = 200, screenHeight = 200;
    float imageWidth = picture.GetWidth();
    float imageHeight = picture.GetHeight();
    //scaling:
    float pictureRatio = imageWidth/ imageHeight;
    float newImageWidth;
    float newImageHeight;
    int aligmentX = 0;
    int aligmentY = 0;
    if (pictureRatio <= 1)
    {
        newImageWidth = imageWidth*(screenHeight/imageHeight);
        newImageHeight = screenHeight;
        aligmentX = (screenWidth-newImageWidth)/2;
    }
    else
    {
        newImageWidth = screenWidth;
        newImageHeight = imageHeight*(screenWidth/imageWidth);
        aligmentY = (screenHeight - newImageHeight)/2;
    }
    //end scaling.
    CDC *screenDC = GetDC();
    CDC mDC;
    mDC.CreateCompatibleDC(screenDC);
    CBitmap bitMap;
    bitMap.CreateCompatibleBitmap(screenDC, screenWidth, screenHeight);
    CBitmap *pob = mDC.SelectObject(&bitMap);
    mDC.SetStretchBltMode(HALFTONE);
    picture.StretchBlt(mDC.m_hDC, aligmentX, aligmentY, newImageWidth, newImageHeight, 0, 0, imageWidth, imageHeight, SRCCOPY);
    mDC.SelectObject(pob);
    /*.......code to convert bitmap to BYTE* ........*/
    /*.......code to send BYTE* over socket........*/       
    //display the bit map
    static_picture.SetBitmap((HBITMAP)bitMap.Detach());
    //clean up
    ReleaseDC(screenDC);
}   

}

所以现在我想再前进一步,并尝试使用套接字。。。是的,我成功地通过套接字发送和接收了简单的char*或CString。
我想做的是:它在另一个对话框(服务器)上显示图像,而不是在这个对话框上显示图片。
不知怎的,我了解到有两种功能听起来很有效:SetBitmapBits()GetBitmapBits()(老实说,我只是从一些来源读到的,不知道它们是否适合我的目标)。

因此,我添加了这段代码,将上面的位图转换为BYTE bmpBuffer:的数组

BITMAP bmpProperties;
bitMap.GetBitmap(&bmpProperties);
int bmpDemension = bmpProperties.bmWidthBytes*bmpProperties.bmHeight;
BYTE* bmpBuffer=(BYTE*)GlobalAlloc(GPTR, bmpDemension);
bitMap.GetBitmapBits(bmpDemension,bmpBuffer);

然后通过套接字发送该数组:

UpdateData(TRUE);
char *socketBuffer = reinterpret_cast<char*>(bmpBuffer);
send(m_ClientSocket, socketBuffer, sizeof(socketBuffer), 0);
//clean up after send
GlobalFree((HGLOBAL)bmpBuffer);

在另一个对话框上。注意:我已经将位图的尺寸硬编码为160000,只是为了简化问题:

void CMyServer2Dlg::OnReceive(){    
char *socketBuffer = new char [1025];
int iLen; 
iLen = recv(m_sConnected, socketBuffer, 1025, NULL);
if(iLen==SOCKET_ERROR)
{
    AfxMessageBox("Could not Receive");
}
else
{
    BYTE* bmpBuffer = reinterpret_cast<BYTE*>(socketBuffer);
    //re-construct the bitmap
    CBitmap clone;
    CDC *screenDC = GetDC();
    CDC mDC;
    mDC.CreateCompatibleDC(screenDC);
    clone.CreateCompatibleBitmap(screenDC, 200, 200);
    clone.SetBitmapBits(160000,bmpBuffer);
    //Picture control(type bitmap) has variable "static_picture"
    static_picture.SetBitmap((HBITMAP)clone.Detach());
    UpdateData(FALSE);
    ReleaseDC(screenDC);
    GlobalFree((HGLOBAL)bmpBuffer);
}
delete socketBuffer;

而且,它就是不起作用。。。请告诉我我在哪里搞砸的?很抱歉发了这么长的帖子。。。。。

我认为最可能的原因是接收器没有获得图片的所有数据。我建议你在发送时把位图的大小放进包里,让接收者得到正确的大小。

下面是一些示例代码。请注意,它们只是为了展示想法,您可能需要进行一些调试以确保它们有效。

步骤1:打包位图的大小。我想这里的大小小于64K,所以使用了int。如果大小可能大于64k,则可能需要使用INT64。

int bmpDemension = bmpProperties.bmWidthBytes*bmpProperties.bmHeight;
int bufferSize = bmpDemension + sizeof(int);
BYTE* bmpBuffer=(BYTE*)GlobalAlloc(GPTR, bufferSize );
bitMap.GetBitmapBits(bmpDemension,bmpBuffer + sizeof(int));
memcpy(bmpBuffer, &bmpDemension, sizeof(int)); // put the size into the head of package.

第二步:发送出去请注意,我在这里使用bufferSize,因为sizeof(bmpBuffer)返回的指针大小是4,而不是空间大小。

UpdateData(TRUE);
char *socketBuffer = reinterpret_cast<char*>(bmpBuffer);
send(m_ClientSocket, socketBuffer, bufferSize , 0);
 //clean up after send
GlobalFree((HGLOBAL)bmpBuffer);

在接收器侧:首先,您读取位图的大小,然后根据数据的大小进行接收。

void CMyServer2Dlg::OnReceive(){    
char socketBuffer[1025];
int iLen; 
iLen = recv(m_sConnected, socketBuffer, sizeof(int), NULL); //read the bigmap size
if(iLen==SOCKET_ERROR)
{
AfxMessageBox("Could not Receive");
}
else
{
int dimension = *((int *) socketBuffer);
char * bitmapBuffer = new char[dimension];
int readSize = dimension;
char * pBuffer = bitmapBuffer;
while (readSize > 0)
{
    int sizeToRead = readSize > sizeof(socketBuffer) ? sizeof(socketBuffer) : readSize;
    iLen = recv(m_sConnected, socketBuffer, sizeToRead , NULL);
    memcpy(pBuffer, socketBuffer, iLen);
    pBuffer += iLen;
    readSize -= iLen;
}
// when the loop done, you shall have all data in bitmapBuffer.
....    
// I leave the remaining code to you.

同样,这些代码只是为了演示这个想法。