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] WriteableBitmap & System.Drawing.Bitmap


Sujet :

Windows Presentation Foundation

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2007
    Messages
    634
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2007
    Messages : 634
    Par défaut [WPF] WriteableBitmap & System.Drawing.Bitmap
    Salut à tous,

    j'essaye désespérément d'intégrer un Bitmap à la position (X, Y) d'un WriteableBitmap, j'ai essayé plusieurs trucs mais rien n'y fait l'image reste noir...

    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
    System.Drawing.Bitmap Bitmap = (Bitmap)System.Drawing.Image.FromStream(Stream);
     
                        WriteableBitmap WriteableBitmap = this.bitmap;
     
                        //BitmapData Data = Bitmap.LockBits(new Rectangle(0, 0, Bitmap.Width, Bitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                        WriteableBitmap.Lock();
     
                        System.Drawing.Bitmap Bmp = new Bitmap(1680, 1050, 1680 * 4, System.Drawing.Imaging.PixelFormat.Format32bppPArgb, WriteableBitmap.BackBuffer);
                        System.Drawing.Graphics BitmapGraphics = System.Drawing.Graphics.FromImage(Bmp);
                        BitmapGraphics.DrawImage(Bitmap, Screen.X, Screen.Y, Bitmap.Width, Bitmap.Height);
                        BitmapGraphics.Dispose();
     
                        Int32Rect Rect = new Int32Rect(Screen.X, Screen.Y, Bitmap.Width, Bitmap.Height);
                        WriteableBitmap.AddDirtyRect(Rect);
                        //Bitmap.UnlockBits(Data);
                        WriteableBitmap.Unlock();
                        Bitmap.Dispose();

    Si quelqu'un a une idée.

    Merci d'avance,
    NeoKript

  2. #2
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Ouhlà, oui, pas étonnant, tout ça ne rime à rien
    Tu charges un bitmap GDI et tu dessines ce bitmap sur lui-même...

    Passe par System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(). Le handle à passer en argument est obtenu via la méthode GetHandle() du bitmap GDI (System.Drawing).

  3. #3
    Membre éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2007
    Messages
    634
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2007
    Messages : 634
    Par défaut
    Salut et merci pour ta réponse.

    J'ai donc fais ceci :

    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
     using (System.Drawing.Bitmap Bitmap = (Bitmap)System.Drawing.Image.FromStream(Stream))
                        {
                            WriteableBitmap.Lock();
                            BitmapSource Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(Bitmap.GetHbitmap(), IntPtr.Zero, new Int32Rect(0, 0, Bitmap.Width, Bitmap.Height), BitmapSizeOptions.FromEmptyOptions());
                            Byte[] Arr = new Byte[Bitmap.Width * Bitmap.Height * WriteableBitmap.BackBufferStride];
                            Source.CopyPixels(Int32Rect.Empty, Arr, WriteableBitmap.BackBufferStride, 0);
                            Int32Rect Rect = new Int32Rect(Screen.X, Screen.Y, Bitmap.Width, Bitmap.Height);
                            WriteableBitmap.WritePixels(Rect, Arr, WriteableBitmap.BackBufferStride, 0);
                            WriteableBitmap.AddDirtyRect(Rect);
                            WriteableBitmap.Unlock();
                        }

    Ça fonctionne, cependant deux petits problèmes :
    - Au bout de 3 minutes : 1Go de Ram utilisée et une jolie exception nous le rappelant (j'ai lu que WriteableBitmap avait des fuites de mémoire dans le Framework 3.5 mais que cela avait été corrigé dans le 4.0 (celui que j'utilise)). Ai-je oublié de libérer les ressources d'une variable ? si oui je ne vois pas. Seul le Bitmap doit être libéré pour moi.
    - C'est pas fluide à 100% et la consommation CPU est de 50% (sur un dual core).

    Des idées ? Merci

  4. #4
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Bonjour.

    Voici deux améliorations pour toi:
    * Tu crées un bitmap WPF à partir d'un bitmap GDI pour ensuite récupérer les pixels bruts du bitmap WPF et les copier dans le WriteableBitmap. Il y a une opération en trop : ne crée pas de BitmapSource et récupère les pixels directement depuis le bitmap GDI (ma proposition de passer par Imaging.Interop visait à se débarrasser du WriteableBitmap, elle ne convient pas pour ton usage).
    * Tu alloues à chaque fois un tableau de plusieurs Mo. Ces tableaux de grande taille sont placés en génération 3 (considérés comme ayant une longue espérance de vie) et le GC ne passe pas les voir souvent, surtout si le CPU est occupé. Pas de fuite mémoire, donc, à mon avis, simplement une allocation trop rapide de tableaux que le GC ne pense pas devoir nettoyer si rapidement. Tu devrais réutiliser le même tableau à chaque fois.

    Enfin, si tout ça ne suffit pas, il faudrait que tu éclaircisses un peu le contexte : à quelle fréquence fais-tu ces opérations et pour quel usage (affichage de la webcam, etc) ? Ça permettra de mieux comprendre le problème et envisager d'autres pistes.

  5. #5
    Membre éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2007
    Messages
    634
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2007
    Messages : 634
    Par défaut
    Salut,

    Merci pour tes réponses.
    J'ai en effet déjà essayer avant de poster ici de passer directement du bitmap au WriteableBitmap. Jai seulement trouve une solution qui copie l'image au debut du buffer de l'image.

    Le principe était le suivant, on lock les bits du system.drawing.bitmap on obtient donc un BitmapData et on effectue un appel à la fonction win32 CopyMemory. Seulement, cela ne fonctionne qu'avec des images de mêmes tailles.

    En mettant le tableau en attribut de classe, je ne vois pas pourquoi le GC passerai plus vite que lorsque le tableau est déclarer dans la méthode.

    Pour information, c'est un application de remote desktop. Je recois les zones de l'écran qui on changés via un check crc et je les envois par socket, et le problème est que l'affichage n'arrive pas a suivre le débit de reception de packets. (1-2 secondes de decallage). Le problème vient je penses du BitmapSource comme tu l'as dit. Mais aussi du dispatchage des packet vers le thread de l'ui pour pouvoir modifier le WriteableBitmap.

    Merci pour ton aide

  6. #6
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    @NeoKript
    Sur la copie directe depuis un bitmap GDI, il n'y a aucune raison que cela ne fonctionne pas, il suffit de passer les bons arguments à WritePixels et d'utiliser la version à cinq arguments :
    WritePixels(Int32Rect sourceRect, Array sourceBuffer, int sourceBufferStride, int destinationX, int destinationY)
    Si c'est le sourceBufferStride qui te pose problème c'est la largeur du bitmap source multipliée par 3 ou 4 (la longueur d'un pixel en octets : 3 pour RGB/BGR/etc, 4 pour RGBA/BGRA/etc). La seule chose à laquelle il faut faire attention c'est que les deux images soient bien au même format (RGB, BGR, etc).


    Sur le fait de conserver le buffer, le GC n'aurait plus besoin de passer puisqu'on conserverait en permanence le même tableau au lieu d'en initialiser un jetable à chaque fois ! Pas d'allocations inutiles.


    Enfin, dernier conseil, si ton apli reçoit par le réseau N mises à jour consécutives pour une même zone de l'écran alors qu'elle est en est encore à traiter la précédente, va t-elle chercher à faire N mises à jour ou directement prendre la dernière ?

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

Discussions similaires

  1. Bitmap pixel System.Drawing
    Par playmobil-62 dans le forum C#
    Réponses: 3
    Dernier message: 06/10/2011, 13h17
  2. Réponses: 10
    Dernier message: 17/09/2010, 15h02
  3. Convertir des System.Drawing.Bitmap en System.Drawing.Icon
    Par ctxnop dans le forum Windows Forms
    Réponses: 1
    Dernier message: 06/12/2008, 00h01
  4. [c#] un erreur dans le system.drawing...
    Par pointer dans le forum DirectX
    Réponses: 3
    Dernier message: 13/07/2005, 20h17
  5. [C#] Conversion System.String en System.Drawing.Color
    Par Silex dans le forum Windows Forms
    Réponses: 6
    Dernier message: 27/04/2005, 08h21

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