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

Windows Presentation Foundation Discussion :

[WPF] Encore les images - question de performances [FAQ]


Sujet :

Windows Presentation Foundation

  1. #1
    Membre à l'essai
    Inscrit en
    Mai 2007
    Messages
    32
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 32
    Points : 22
    Points
    22
    Par défaut [WPF] Encore les images - question de performances
    Salut

    j'ai un gros souci de perfs, et je ne sais pas trop comment y remédier :

    En regardant la taille de RAM utilisée par une appli WPF de base, on est déjà à plus de 20 Mo dès le lancement d'une appli, même s'il n'y a rien du tout sur la Form...déjà là je trouve ça énorme, mais bon...c'est du .Net et même en Winforms classique ça prenait déjà beaucoup de mémoire.

    Le problème que j'ai c'est lorsque je charge un Bitmap dans un contrôle Image. Là on passe tout de suite de 20 Mo à 40 Mo utilisés, sachant que mon Bitmap (chargé à partir du disque via son Uri) pèse environ 1 Mo...je me dis que forcément le contrôle Image instancie un paquet de propriétés lors de son chargement, mais quand même !!! Où sont utilisés les 19 mo restants ??? Bizarrement, si j'en charge une deuxième, je passe à environ 50 Mo utilisés, puis à 68 mo pour une troisième...

    Bref, sans tout le temps regarder mon gestionnaire de tâches, et en connaissant un chouilla comment fonctionne le Garbage Collector, ça me turlupine assez pour que je me demande vraiment si WPF a été pensé pour la simplicité d'usage...parce que depuis que je travaille avec, je n'ai pas arrêté de devoir contourner les moyens classiques, ne serait-ce que pour afficher des miniatures via une virtualisation à la mano pour ne pas tout charger en mémoire...

    J'aimerais savoir en fait quel est pour vous le meilleur moyen de charger une image de grande taille (réduite lors de l'affichage - stretch quoi...) sans pour autant faire gonfler de façon exponentielle la mémoire vive utilisée par l'appli.

    Pour ma part, je me suis penché vers l'utilisation d'ImageBrushes Freezées, mais c'est assez chiant si on veut par exemple binder la taille de l'image affichée à un slider (bah ouais, on doit binder le slider avec la taille du border contant la brush...relou...)

    enfin bon....help....

  2. #2
    Rédacteur
    Avatar de Thomas Lebrun
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    9 161
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 9 161
    Points : 19 434
    Points
    19 434
    Par défaut
    Essaye de jetter un oeil dans le document que tu trouveras ici: http://blogs.msdn.com/timothyc/archi...rformance.aspx

    Sinon, tu as essayé de passer ton application dans l'outil WPF Performance Suite pour voir ce qu'il en ressortait ?
    http://wpf.netfx3.com/files/folders/...ntry10880.aspx

  3. #3
    Membre à l'essai
    Inscrit en
    Mai 2007
    Messages
    32
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 32
    Points : 22
    Points
    22
    Par défaut
    Re Thomas

    Décidément c'est ta section le WPF

    J'avais déjà lu le document sur les perfs, mais malheureusement il n'est rien précisé au niveau du chargement des images, sauf le fait que charger une ImageBrush que l'on Freeze par la suite permette de moins consommer de ressources. Le problème par contre est qu'on ne peut plus utiliser un Border ou un Rectangle, qui a été rempli avec cette ImageBrush, de la même manière qu'un contrôle Image.

    Pour ce qui est de l'outil de perfs (WPFPerf), je comprends rien à son utilisation et j'ai essayé de l'utiliser sur mon appli, mais rien ne sort comme info...si je choisis le "Working Set Analyzer" pour voir l'usage de la mémoire puis que je choisis mon appli, lors de la capture, je n'ai rien qui s'affiche. Il n'y a que l'outil Perforator qui fonctionne, mais ça ne me donne pas grand chose, à part le fait qu'aucune zone de mon appli ne fait appel à du rendu hardware-accelerated (loool) et que j'ai un framerate entre 20 et 30

    Y'a un truc que j'aurais oublié par hasard ???

  4. #4
    Rédacteur
    Avatar de Thomas Lebrun
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    9 161
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 9 161
    Points : 19 434
    Points
    19 434
    Par défaut
    Citation Envoyé par BruceWayne
    Re Thomas

    Décidément c'est ta section le WPF
    Oui, avec C# 3 / Linq
    As-tu essayer de charger bcp d'images, histoire de voir si la consommation mémoire augmente toujours un peu plus à chaque fois ? Si oui, c'est que tu as une fuite mémoire quelque part alors....

  5. #5
    Membre à l'essai
    Inscrit en
    Mai 2007
    Messages
    32
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 32
    Points : 22
    Points
    22
    Par défaut
    J'ai trouvé, il faut supprimer chaque objet Bitmap chargé comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Bitmap bmpF = new Bitmap(@"D:\__IMAGES\test.jpg");
    IntPtr ptrBmp = bmpf.GetHbitmap();
    BitmapSource bmpSrc = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(ptrBmp, IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
    this.image1.Source = this.bmpSrc;
    DeleteObject(ptrBmp);
    this.bmpSrc = null;
    et la méthode DeleteObject() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    [System.Runtime.InteropServices.DllImport("gdi32.dll")]
    public static extern bool DeleteObject(IntPtr hObject);


    J'ai bindé un slider à un effet de luminosité/contraste avec la librairie AForge et j'utilise pas plus de 32 Mo au final, après avoir fait joujou avec le slider. Même tout du long des applications des filtres, ça bouge que jusqu'à 40 Mo en tout au final !

    Nickel

    ++

  6. #6
    Rédacteur
    Avatar de Thomas Lebrun
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    9 161
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 9 161
    Points : 19 434
    Points
    19 434
    Par défaut
    Faudra penser à mettre ca dans la FAQ

  7. #7
    Membre à l'essai
    Inscrit en
    Mai 2007
    Messages
    32
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 32
    Points : 22
    Points
    22
    Par défaut
    Alors en fait, l'astuce présentée vaut le coup si on souhaite travailler sur des Bitmaps temporaires pour par exemple effectuer des transformations sur les pixels. Si on souhaite juste charger une seule image, il faut simplement utiliser un BitmapImage, dont un des constructeurs prends une URI :

    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    BitmapImage bmpImage = new BitmapImage(new Uri(chemin_image));
    this.controleImage.Source = bmpImage;

    En fait, cette portion de code suffit à ne pas trop faire gonfler la mémoire utilisée, mais devient trop limitée dès lors qu'on veut travailler sur le Bitmap (en fait on peut pas ...). Si on crée un User Control qui charge une image seule en utilisant un BitmapImage comme ci-dessus, lors de la destruction du Control, le BitmapImage sera détruit avec, ce qui n'arrive pas si on charge l'image avec un objet Bitmap+BitmapSource (ici GDI laisse l'objet en mémoire non-managée).

    Voici un bout de code complet d'une form qui permet de voir l'utilisation de la RAM sur des opérations de luminosité/contraste avec un Bitmap temporaire :

    ATTENTION, pour le tester il faut utiliser la librairie AForge dispo ici http://code.google.com/p/aforge/ et rajouter les références (Aforge.dll et Aforge.Imanging.dll) au projet.

    Code c# : 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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
    using System.Drawing;
    using System.Drawing.Imaging;
     
     
    namespace Bitmap_LuminositeContraste
    {
        /// <summary>
        /// Interaction logic for Window1.xaml
        /// </summary>
     
        public partial class Window1 : System.Windows.Window
        {
     
            private Bitmap bmpOriginal;
            private Bitmap bmpf;
            private BitmapSource bmpSrc;
     
            public Window1()
            {
                InitializeComponent();
     
                this.sliderBrightness.ValueChanged += new RoutedPropertyChangedEventHandler<double>(slider_ValueChanged);
                this.sliderContrast.ValueChanged += new RoutedPropertyChangedEventHandler<double>(sliderContrast_ValueChanged);
     
                this.bmpOriginal = new Bitmap(@"D:\__IMAGES\Elene.jpg");
                slider_ValueChanged(this, new RoutedPropertyChangedEventArgs<double>(0,0));
                sliderContrast_ValueChanged(this, new RoutedPropertyChangedEventArgs<double>(0, 0));
     
            }
     
     
            // CONTRASTE
            void sliderContrast_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
            {
                this.bmpf = new Bitmap(this.bmpOriginal, new System.Drawing.Size(this.bmpOriginal.Width / 2, this.bmpOriginal.Height / 2));
     
                AForge.Imaging.Filters.ContrastCorrection br = new AForge.Imaging.Filters.ContrastCorrection(e.NewValue);
                br.ApplyInPlace(this.bmpf);
     
                IntPtr ptrBmp = bmpf.GetHbitmap();
                this.bmpSrc = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(ptrBmp, IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
                this.image1.Source = this.bmpSrc;
     
                DeleteObject(ptrBmp);
                this.bmpSrc = null;
                this.bmpf.Dispose();
            }
     
     
            // LUMINOSITE
            void slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
            {
     
                this.bmpf = new Bitmap(this.bmpOriginal, new System.Drawing.Size(this.bmpOriginal.Width/2, this.bmpOriginal.Height/2));
     
                AForge.Imaging.Filters.BrightnessCorrection br = new AForge.Imaging.Filters.BrightnessCorrection(e.NewValue);
                br.ApplyInPlace(this.bmpf);
     
                IntPtr ptrBmp = bmpf.GetHbitmap();
                this.bmpSrc = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(ptrBmp, IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
                this.image1.Source = this.bmpSrc;
     
                DeleteObject(ptrBmp);
                this.bmpSrc = null;
                this.bmpf.Dispose();
     
            }
     
            [System.Runtime.InteropServices.DllImport("gdi32.dll")]
            public static extern bool DeleteObject(IntPtr hObject);
     
     
        }
    }

    En espérant avoir été assez clair...c'est pas évident ces histoires de perf sous WPF...

    PS : Thomas, comment on fait pour rajouter tout ça à la FAQ ? Et au fait, je te remercie pour un des tes posts sur ton blog concernant le Drag and Drop, ça m'a bien été utile hier

  8. #8
    Rédacteur
    Avatar de Thomas Lebrun
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    9 161
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 9 161
    Points : 19 434
    Points
    19 434
    Par défaut
    Citation Envoyé par BruceWayne
    PS : Thomas, comment on fait pour rajouter tout ça à la FAQ ?
    C'est nous qui allons nous charger de cela

    Et au fait, je te remercie pour un des tes posts sur ton blog concernant le Drag and Drop, ça m'a bien été utile hier
    Ravi de t'avoir aidé

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Débutant] [WPF]Lister les images d'un dossier
    Par Hoplite-Studio dans le forum C#
    Réponses: 2
    Dernier message: 18/05/2012, 11h53
  2. Réponses: 5
    Dernier message: 15/05/2007, 14h53
  3. Encore une petite question sur les sockets...
    Par damien99 dans le forum MFC
    Réponses: 4
    Dernier message: 15/02/2006, 14h22
  4. [Debutante][image]questions sur les images
    Par misstinkiete dans le forum 2D
    Réponses: 2
    Dernier message: 25/07/2005, 21h23
  5. [Performance] - Blob ou pas pour les images d'un site ?
    Par ShinJava dans le forum SQL Procédural
    Réponses: 2
    Dernier message: 04/07/2005, 17h32

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