IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

MFC Discussion :

Différentes méthodes d'affichage d'un bitmap


Sujet :

MFC

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    164
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 164
    Points : 161
    Points
    161
    Par défaut Différentes méthodes d'affichage d'un bitmap
    bonsoir, j'ai terminé récemment un petit programme qui permet l'ouverture d'une image bitmap constituée d'un fond noir et d'un petit objet couleur, l'utilisateur peut alors choisir un mouvement à appliquer à l'objet (exemple rotation), ainsi le programme calcule la trajectoire, crée les images successives et affiche les images à une vitesse plus ou moins grande (de manière à donner l'impression de mouvement) grace à un timer.

    J'ai utilisé pour cela une classe CColorImage comportant la méthode d'affichage suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
    void CColorImage::Afficher(CDC* pDC,int x,int y)
    {
    	unsigned int hauteur;
     
    	hauteur=getHauteur();
     
    	int diff=0,ligne=0,j=0;
    	BITMAPINFO *info;
    	BITMAPINFOHEADER infoHeader;
    	infoHeader.biSize=sizeof(infoHeader);
    	infoHeader.biSizeImage=0;
    	infoHeader.biClrUsed = 0;
    	infoHeader.biHeight = getHauteur();
    	infoHeader.biWidth =getLargeur();
    	infoHeader.biCompression = 0;
    	infoHeader.biBitCount = 24;
    	infoHeader.biPlanes=1;
    	info=(BITMAPINFO*)new BYTE[sizeof(BITMAPINFOHEADER)];
    	memcpy( info, &infoHeader, sizeof(BITMAPINFOHEADER) );
     
     
    	unsigned char * pix;
    	pix=new unsigned char[3*(getLargeur()*getHauteur())];
     
     
    	for(int i=0;i<getHauteur();i++) {
    		for(int j=0;j<getLargeur();j++){
    			for(int k=0; k<3;k++) {
    				pix[3*j+3*i*getLargeur()+k]=m_pppucLigne[getHauteur()-1-i][j][2-k];
    			}
    		}
    	}
     
    	HDC  hdc = pDC->GetSafeHdc();
        StretchDIBits( hdc, x, y,getLargeur(),getHauteur(),0,0,getLargeur(),getHauteur(),pix,info,DIB_RGB_COLORS,SRCCOPY );
    	delete pix;
    	pix=NULL;
    }
    j'utilise ainsi la fonction StretchDIBits. Mon programme marche bien le seul problème est que cette fonction d'affichage est relativement lente d'où un effet de mise à jour de la vue entre l'affichage de 2 images successives pas esthétique du tout.

    Je voudrais savoir s'il existe d'autres techniques d'affichage d'image bmp plus performantes?

    au niveau des mfc j'ai vu qu'il existe le CPictureControl mais celui-ci ne peut etre initialisé qu'à partir d'une ressource qu'il faut ajouter au projet or je ne connais pas d'avance mes images donc impossibilité d'utiliser cette méthode.

    merci pour toute réponse éventuelle

  2. #2
    Membre confirmé Avatar de stephdim
    Profil pro
    Inscrit en
    Août 2007
    Messages
    462
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 462
    Points : 521
    Points
    521
    Par défaut
    salut,

    utilises plutot une section DIB --> voir fonction CreateDIBSection() dans la MSDN.
    n'allouer la mémoire consacrée au bitmap qu'une fois pour toute et non à chaque rafraichissement.
    pour l'affichage, utiliser la fonction BitBlt().

    sinon tu peux passer par DirectDraw ou d'autres libs comme SDL ...

    @+

  3. #3
    Expert éminent sénior
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 381
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 381
    Points : 20 452
    Points
    20 452
    Par défaut
    j'utilise ainsi la fonction StretchDIBits. Mon programme marche bien le seul problème est que cette fonction d'affichage est relativement lente d'où un effet de mise à jour de la vue entre l'affichage de 2 images successives pas esthétique du tout.
    ll est souhaitable de créer une bitmap /HDC en mémoire et dessiner d'abord dedans puis faire un simple BitBlt ou StretchBlt vers le CDC obtenu dans OnDraw().
    C'est comme cela que je procéde et ça fonctionne parfaitement.

    Sinon pour plus de performances on peut effectivement appeler DirectDraw en fenêtré mais la fenêtre et controles seront plus lents à être affichés

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    164
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 164
    Points : 161
    Points
    161
    Par défaut
    merci pour vos réponses.
    pour ce qui est de l'allocation de la mémoire je procède de la manière suivante :
    je crée (avant l'affichage) un tableau d'image, j'alloue de l'espace mémoire pour chacune de ces images, je les calcule et les stocke dans le tableau. cela pompe énormément sur la ram mais au moins je n'alloue pas de nouvelles zones mémoires entre chaque rafraichissement, j'affiche juste les images de mon tableau les unes apres les autres. quelle méthode me conseillerais-tu stephdim ?

    pour ce qui est de l'affichage vous semblez me conseiller de passer par un BitBlt mais je n'ai pas bien compris l'explication de Mat.M, aurais-tu le code d'affichage d'un bitmap que tu utilises habituellement ? je pourrais ainsi comparer au niveau vitesse d'affichage .
    merci!

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    164
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 164
    Points : 161
    Points
    161
    Par défaut
    salut, j'ai un peu avancé en essayant d'utiliser CreateDIBSection et BitBlt mais j'ai encore quelques soucis, mon code est le suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    unsigned char * pix;
    	pix=new unsigned char[3*(getLargeur()*getHauteur())];
     
     
    	for(int i=0;i<getHauteur();i++) {
    		for(int j=0;j<getLargeur();j++){
    			for(int k=0; k<3;k++) {
    				pix[3*j+3*i*getLargeur()+k]=m_pppucLigne[getHauteur()-1-i][j][2-k];
    			}
    		}
    	}
     
    	HDC  hdc = pDC->GetSafeHdc();
    	HDC bitmapDC = CreateCompatibleDC(hdc);
     
    	HBITMAP im = CreateDIBSection(bitmapDC,info,DIB_RGB_COLORS,(void**)&pix, NULL,0);
     
    	BitBlt(hdc,0,0,getLargeur(),getHauteur(),bitmapDC ,0,0,SRCCOPY);
    le programme plante dès l'affichage

    je ne sais pas à quoi correspondent certains paramètres d'entrée de ces fonctions, à la base j'ai :
    - mon handle sur le device context correspondant à l'écran (pDC->GetSafeHdc()) ( dites_moi si je me trompe)
    - un handle créé à partir du précédent dans lequel je veux stocker l'image en mémoire ( HDC bitmapDC = CreateCompatibleDC(hdc))
    - mon tableau contenant les données de l'image : unsigned char * pix
    - info qui est un pointeur sur BITMAPINFO

    je crée tout d'abord mon HBITMAP avec la fonction CreateDIBSection, en premier paramètre je passe mon bitmapDC, je ne suis pas sûr de moi.

    Puis j'utilise la fonction BitBlt pour afficher mon image, cette fonction comprend deux handles, le premier sur le DC de destination et l'autre sur le DC source, c'est là que je ne sais pas quels handles utiliser??

    Pour le destination j'ai mis le hdc (écran) et pour la source bitmapDC (mémoire) mais le programme plante directement.

    J'ai besoin d'aide pour mieux comprendre l'utilisation de ces fonctions, svp , merci

  6. #6
    Membre confirmé Avatar de stephdim
    Profil pro
    Inscrit en
    Août 2007
    Messages
    462
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 462
    Points : 521
    Points
    521
    Par défaut
    Salut,

    Une DIB Section est un bitmap où tu peux accéder à sa mémoire, donc modifier directement les pixels.
    C'est Windows qui gère l'allocation / libération de la mémoire, donc pas de new ni delete à faire.
    Maintenant je ne sais pas si ça convient à ton besoin, ça dépend de comment sont créées tes images ...
    Voilà à quoi ça peut convenir :

    - tu créés une DIB Section à l'initialisation de ton programme (création de la fenetre par exemple)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    BITMAPINFOHEADER bmih;
    bmih.biSize=sizeof(bmih);
    bmih.biWidth=320;
    bmih.biHeight=-240;  // négatif pour du haut vers le bas / positif pour du bas vers le haut
    bmih.biPlanes=1;
    bmih.biBitCount=24;
    bmih.biCompression=BI_RGB;
    bmih.biSizeImage=0;
    bmih.biXPelsPerMeter=0;
    bmih.biYPelsPerMeter=0;
    bmih.biClrUsed=0;
    bmih.biClrImportant=0;
     
    LPBYTE pBuffer;
    HBITMAP hBitmap=CreateDIBSection(NULL,(BITMAPINFO*)&bmih,DIB_RGB_COLORS,(void**)&pBuffer,NULL,0);
     
    if (hBitmap==NULL)
      AfxThrowResourceException();  // erreur
    Dans l'exemple ci dessus, je créé un bitmap 24 bits de 320x240 pixels.
    hBitmap est le handle de ce bitmap à conserver, il te servira pour l'affichage et surtout pour le nettoyage (libération mémoire) à la fin.
    Il serait pas mal de l'attacher à un objet CBitmap pour rester dans la philosophie MFC.

    Si la fonction CreateDIBSection a réussie, pBuffer pointe sur la mémoire du bitmap. tu peux donc t'en servir pour écrire tes pixels.

    - quand tu as fini de dessiner ton image dans le buffer, il faut rafraichir l'écran pour faire apparaitre ta nouvelle image. Là on peut exploiter le mécanisme de Windows si c'est une fenetre par le message WM_PAINT, ou dessiner directement.

    pour simplifier, je dessine directement :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    CClientDC dc(pWnd);  // pWnd est le pointeur sur la fenetre
    CDC memdc;  // Memory Device Context
    if (memdc.CreateCompatibleDC(&dc))
    {
      HGDIOBJ hOldBitmap=SelectObject(memdc.m_hDC,hBitmap);
      dc.BitBlt(0,0,320,240,&memdc,0,0,SRCCOPY);
      SelectObject(memdc.m_hDC,hOldBitmap);
    }
    else
      AfxThrowResourceException();  // erreur
    Par le message WM_PAINT, il faut l'intercepter (gestionnaire OnPaint) et remplacer CClientDC par CPaintDC... et à chaque fois que tu veux rafraichir, faire un pWnd->Invalidate(FALSE) suivi d'un pWnd->UpdateWindow()

    - pour finir il faut libérer les ressources quand tu n'en as plus besoin (à la destruction de la fenetre par exemple), juste faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    DeleteObject(hBitmap);
    voila pour le coté technique d'une DIB Section, maintenant il faut que tu évites ce genre de boucle, si tu veux que ça tourne plus vite :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    for(int i=0;i<getHauteur();i++) {
    		for(int j=0;j<getLargeur();j++){
    			for(int k=0; k<3;k++) {
    				pix[3*j+3*i*getLargeur()+k]=m_pppucLigne[getHauteur()-1-i][j][2-k];
    			}
    		}
    	}
    à remplacer par un simple memcpy() beaucoup plus performant ...
    mais l'idéal serait de composer la nouvelle image directement dans le buffer

    @+

Discussions similaires

  1. Réponses: 25
    Dernier message: 27/03/2006, 11h00
  2. Réponses: 4
    Dernier message: 28/02/2006, 14h25
  3. Boite dialogue + Affichage d'un bitmap
    Par gids01 dans le forum MFC
    Réponses: 8
    Dernier message: 23/11/2005, 16h50
  4. Méthode d'affichage avec MFC
    Par Blobette dans le forum MFC
    Réponses: 2
    Dernier message: 09/03/2005, 16h48
  5. Affichage d'une bitmap et de l'heure
    Par nanarr dans le forum Assembleur
    Réponses: 14
    Dernier message: 16/04/2004, 22h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo