C++ [MFC/C+;+;]发送CBitmap';s位在套接字上,并在接收器端重新构造它
我是MFC的新手,尝试通过一个基于VS2008的MFC对话项目来学习它。以下是我所做的档案: 首先,我成功地将文件夹中的图片列表显示到列表框控件中。之后,我还处理了listbox每一行上的click事件,以加载图片并将其显示到右侧的picture控件(键入位图)。为了便于理解,您可以看到下图:C++ [MFC/C+;+;]发送CBitmap';s位在套接字上,并在接收器端重新构造它,c++,mfc,asyncsocket,C++,Mfc,Asyncsocket,我是MFC的新手,尝试通过一个基于VS2008的MFC对话项目来学习它。以下是我所做的档案: 首先,我成功地将文件夹中的图片列表显示到列表框控件中。之后,我还处理了listbox每一行上的click事件,以加载图片并将其显示到右侧的picture控件(键入位图)。为了便于理解,您可以看到下图: 这是代码。注意m_ListCtrl和static_picture是列表框和图片控件的变量: void CMyClientDlg::OnLbnSelchangeList1(){ CString imag
这是代码。注意
m_ListCtrl
和static_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);
}
然后通过套接字发送该数组:
UpdateData(TRUE);
char *socketBuffer = reinterpret_cast<char*>(bmpBuffer);
send(m_ClientSocket, socketBuffer, sizeof(socketBuffer), 0);
//clean up after send
GlobalFree((HGLOBAL)bmpBuffer);
UpdateData(真);
char*socketBuffer=reinterpret_cast(bmpBuffer);
发送(m_ClientSocket,socketBuffer,sizeof(socketBuffer),0);
//发送后清理
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;
void CMyServer2Dlg::OnReceive(){
char*socketBuffer=新字符[1025];
内伊伦;
iLen=recv(m_已连接,socketBuffer,1025,NULL);
如果(iLen==SOCKET\u错误)
{
AfxMessageBox(“无法接收”);
}
其他的
{
字节*bmpBuffer=重新解释强制转换(socketBuffer);
//重新构造位图
CBitmap克隆;
CDC*screenDC=GetDC();
疾病预防控制中心;
mDC.CreateCompatibleDC(screenDC);
CreateCompatibleBitmap(screenDC,200200);
克隆.SetBitmapBits(160000,bmpBuffer);
//图片控件(位图类型)具有变量“静态图片”
static_picture.SetBitmap((HBITMAP)clone.Detach());
更新数据(假);
ReleaseDC(screenDC);
GlobalFree((HGLOBAL)bmpBuffer);
}
删除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);
同样,这些代码只是为了演示这个想法。在研究解决方案时使用+1(是的,我认为GetBitmapBits和SetBitmapBits是正确的函数)。但是,“不工作”是什么意思?谢谢你的回复。在接收端,它只显示200x200黑色,而不是我在发送端单击的图像。我还尝试在发送端重新构建位图进行测试,它工作正常。如果错误,请更正我。你的接收缓冲区是1025,位图大小是160000。缓冲区足够大吗?还有,甚至虽然您要求一次接收1025个字节,但您可能无法全部接收到它们-您可能需要多次致电recv以获取所有字节。是否有理由不将位图作为位图文件发送/接收?感谢您的帮助!我将尝试您的建议并告诉您结果。这很有效!您非常棒。不过,我们需要清除错误每次绘制图像后都会出现socketBuffer,因为客户端可能会单击另一个图像并导致崩溃。无论如何,非常感谢您的帮助,我不敢相信我在开始时错过了指针大小这样基本的东西…很好学。是的,关于清理的事情,您是对的。很容易忘记。欢迎您顺便问一下:Dbtw,有什么方法可以避免循环?因为这会严重影响性能。如果客户端点击太快,服务器端可能会挂起。Windows/Visual Studio上的
int
是4个字节。它最多可以表示2^31-1的值。64k-1将是无符号16位数据类型的最大可表示值(例如unsigned short
)。指针可以是4或8个字节。除此之外,您的大小计算是错误的。它完全忽略了每像素位值以及扫描线填充。此解决方案需要大量运气才能工作。
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.