2016-05-04 3 views
2

Je suis nouveau avec MFC et essaye de l'apprendre avec un projet de base de dialogue MFC sur VS2008. Voici les archives que j'ai faites:[MFC/C++] Envoi des bits de CBitmap sur le socket, et reconstruction du côté récepteur

D'abord, j'ai réussi à afficher une liste d'images d'un dossier à un contrôle Listbox. Après cela, j'ai également géré l'événement click sur chaque ligne de la liste pour charger et afficher l'image dans le Picture Control (tapez Bitmap) sur le côté droit. Vous pouvez voir l'image ci-dessous pour une compréhension facile: Please click here for the image of my MFC dialog

Voici le code. Notez m_ListCtrl et static_picture sont des variables de la zone de liste et le contrôle de l'image:

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

}

Alors maintenant, je voudrais avancer d'un pas de plus, et a essayé de travailler avec prise ... et oui, je réussi envoyé et reçu simple char * ou CString sur socket.
Ce que je veux faire est: à la place d'afficher l'image sur cette boîte de dialogue, il montre l'image sur l'autre boîte de dialogue (serveur).
D'une manière ou d'une autre j'ai appris qu'il y a 2 funtions qui fonctionnent bien: SetBitmapBits() et GetBitmapBits() (je l'ai juste lu juste sur quelque source et n'ai aucune idead si elles conviennent à mon but ici).

Alors, j'ai ajouté ce morceau de code pour transformer le bitmap ci-dessus dans un tableau de BYTE bmpBuffer:

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

envoyer ensuite ce tableau sur la douille:

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

autre boîte de dialogue. Note: Je le demension hardcoded du bitmap à 160000, pour simplifier le problème:

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; 

Et, ça ne marche pas ... S'il vous plaît me dire où ai-je gâcher? Et désolé pour le poste long .....

+0

Avoir un +1 pour rechercher des solutions (oui, GetBitmapBits et SetBitmapBits sont les bonnes fonctions, je pense). Mais, que voulez-vous dire par "ne fonctionne pas"? – immibis

+0

Merci pour votre réponse. Du côté du récepteur, il n'affiche que la couleur noire 200x200, pas l'image sur laquelle j'ai cliqué du côté de l'expéditeur. J'ai également essayé de reconstruire la carte de bits du côté de l'expéditeur pour les tests et cela fonctionne normalement. –

+1

Corrigez-moi si c'est le cas. Votre tampon de réception est 1025, et votre taille de bitmap est 160000. Le tampon est-il assez gros? –

Répondre

0

Je pense que la raison la plus possible est que votre récepteur ne reçoit pas toutes les données de l'image. Je vous suggère de mettre une taille de l'image bitmap dans le paquet en l'envoyant, pour que le récepteur obtienne la bonne taille.

Voici quelques exemples de code. Soyez conscient qu'ils sont juste pour montrer l'idée, vous devrez peut-être déboguer pour s'assurer qu'ils fonctionnent.

étape 1: empaquetez la taille de bitmap. Je suppose ici que la taille est inférieure à 64K, donc un int est utilisé. Si la taille peut être supérieure à 64 Ko, vous pouvez utiliser 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. 

étape 2: l'envoyer Soyez au courant, j'utilise bufferSize ici, parce que sizeof (bmpBuffer) retourne la taille du pointeur, ce qui est 4, pas la taille de l'espace.

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

A côté récepteur: Tout d'abord, vous avez bien lu la taille du bitmap, puis ne reçoivent en fonction de la taille des données.

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. 

Encore une fois, ces codes sont juste pour démo l'idée.

+0

Nous vous remercions de votre aide! Je vais essayer votre suggestion et vous dire le sortir. –

+0

Ça marche! Tu es incroyable. Cependant, nous devons effacer le socketBuffer après chaque dessin de l'image, car le client peut cliquer sur une autre image et provoquer un plantage. Quoi qu'il en soit, merci beaucoup pour votre aide, je ne peux pas croire que j'ai manqué quelque chose d'aussi basique que la taille du pointeur au début ... Bon à apprendre. –

+0

Oui, vous avez raison à propos de la chose de nettoyage. Facile à oublier. Vous êtes les bienvenus btw: D –