begin process at 2008 05 09 21:17:10
1 168 892 membres
481 nouveaux aujourd'hui
13 952 membres club

Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum.
Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on ose pas poser une question, ça c'est une erreur !

WRAPPER .NET 2.0 POUR LES CACHEDBITMAP DE GDI+


Information sur la source

Catégorie :Graphique Source .NET ( DotNet ) Classé sous : CachedBitmap, gdi, dotnet 2, managed, Graphics Niveau : Initié Date de création : 27/03/2008 Date de mise à jour : 27/03/2008 12:22:21 Vu / téléchargé: 1 032 / 46

Note :
Aucune note

Commentaire sur cette source (1)
Ajouter un commentaire et/ou une note

Description

Si le Framework .NET 3.0 et supérieur possèdent une classe CachedBitmap managée, ce n'est malheureusement pas le cas de .NET 2.0.
Ma petite source est là pour y remédier : elle permet d'utiliser les CachedBitmap pour dessiner rapidement sur un objet Graphics.
Les CachedBitmap sont censées être plus rapides à dessiner qu'en passant par la méthode Graphics.DrawImage()
Suite à la demande de Kevin Ory, je me suis mis au travail et voice cette source.
Elle est composée de 2 parties : une librairie ManagedCachedBitmap en C# et une petite application de test en VB .NET

Source

  • using System;
  • using System.Collections.Generic;
  • using System.Text;
  • using System.Runtime.InteropServices;
  • using System.Drawing;
  • using System.Reflection;
  • namespace ManagedCachedBitmap
  • {
  • /// <summary>
  • /// Wrapper pour les CachedBitmap non managés de GDI+
  • /// </summary>
  • public class ManagedCachedBitmap
  • {
  • [DllImport("gdiplus.dll")]
  • public static extern int GdipCreateCachedBitmap(IntPtr pBitmap, IntPtr pGraphics, ref IntPtr pCachedBitmap);
  • [DllImport("gdiplus.dll")]
  • public static extern int GdipDrawCachedBitmap(IntPtr pGraphics, IntPtr pCachedBitmap, int x, int y);
  • [DllImport("gdiplus.dll")]
  • public static extern int GdipDeleteCachedBitmap(IntPtr pCachedBitmap);
  • private Bitmap _cachedBitmap;
  • private Graphics _graphics;
  • private IntPtr _pCachedBitmap;
  • private FieldInfo _Bitmapfi;
  • private FieldInfo _Graphicsfi;
  • private IntPtr _pBitmapfi;
  • private IntPtr _pGraphicsfi;
  • private Boolean _isLoaded = false;
  • /// <summary>
  • /// Constructeur.
  • /// </summary>
  • /// <param name="b">un objet Bitmap</param>
  • /// <param name="g">un objet Graphics</param>
  • public ManagedCachedBitmap(Bitmap b, Graphics g)
  • {
  • this.Init(b, g);
  • }
  • /// <summary>
  • /// Destructeur
  • /// </summary>
  • ~ManagedCachedBitmap()
  • {
  • this.Delete();
  • }
  • /// <summary>
  • /// Utilisé pour initialiser un CachedBitmap à partir d'un Graphics et d'un Bitmap
  • /// </summary>
  • /// <param name="b">un objet Bitmap</param>
  • /// <param name="g">un objet Graphics</param>
  • public void Init(Bitmap b, Graphics g)
  • {
  • if (_isLoaded) this.Delete();
  • this._cachedBitmap = b;
  • this._graphics = g;
  • this._Bitmapfi = typeof(Bitmap).GetField("nativeImage", BindingFlags.Instance | BindingFlags.NonPublic);
  • this._pBitmapfi = (IntPtr)this._Bitmapfi.GetValue(this._cachedBitmap);
  • this._Graphicsfi = typeof(Graphics).GetField("nativeGraphics", BindingFlags.Instance | BindingFlags.NonPublic);
  • this._pGraphicsfi = (IntPtr)this._Graphicsfi.GetValue(this._graphics);
  • GdipCreateCachedBitmap(this._pBitmapfi, this._pGraphicsfi, ref this._pCachedBitmap);
  • this._isLoaded = true;
  • }
  • /// <summary>
  • /// Modifie seulement le Bitmap sans avoir à tout refaire (plus rapide que la méthode Init() ). Utile pour faire une animation par exemple.
  • /// </summary>
  • /// <param name="b">Un objet Bitmap</param>
  • /// <returns></returns>
  • /// <remarks>La mise à jour ne sera pas effectuée si la méthode</remarks>
  • public Boolean InitBitmap(Bitmap b)
  • {
  • if (!_isLoaded) return false;
  • this.Delete();
  • this._cachedBitmap = b;
  • this._Bitmapfi = typeof(Bitmap).GetField("nativeImage", BindingFlags.Instance | BindingFlags.NonPublic);
  • this._pBitmapfi = (IntPtr)this._Bitmapfi.GetValue(this._cachedBitmap);
  • GdipCreateCachedBitmap(this._pBitmapfi, this._pGraphicsfi, ref this._pCachedBitmap);
  • this._isLoaded = true;
  • return true;
  • }
  • /// <summary>
  • /// Modifie seulement le Graphics où l'on dessinera le Bitmap (plus rapide que la méthode Init() ).
  • /// </summary>
  • /// <param name="g"></param>
  • /// <returns></returns>
  • public Boolean InitGraphics(Graphics g)
  • {
  • if (!_isLoaded) return false;
  • this.Delete();
  • this._graphics = g;
  • this._Graphicsfi = typeof(Graphics).GetField("nativeGraphics", BindingFlags.Instance | BindingFlags.NonPublic);
  • this._pGraphicsfi = (IntPtr)this._Graphicsfi.GetValue(this._graphics);
  • GdipCreateCachedBitmap(this._pBitmapfi, this._pGraphicsfi, ref this._pCachedBitmap);
  • this._isLoaded = true;
  • return true;
  • }
  • /// <summary>
  • /// Définit ou renvoie le Bitmap utilisé
  • /// </summary>
  • public Bitmap Bitmap
  • {
  • get
  • {
  • return _cachedBitmap;
  • }
  • set
  • {
  • this._cachedBitmap = value;
  • this.InitBitmap(this._cachedBitmap);
  • }
  • }
  • /// <summary>
  • /// Définit ou renvoie le Graphics utilisé
  • /// </summary>
  • public Graphics Graphics
  • {
  • get
  • {
  • return _graphics;
  • }
  • set
  • {
  • this._graphics = value;
  • this.InitGraphics(this._graphics);
  • }
  • }
  • /// <summary>
  • /// Vrai si l'initialisation du CachedBitmap s'est déroulée correctement
  • /// </summary>
  • public bool IsLoaded
  • {
  • get
  • {
  • return _isLoaded;
  • }
  • }
  • /// <summary>
  • /// Dessine le Bitmap sur l'objet Graphics aux coordonnées (0 ; 0)
  • /// </summary>
  • /// <returns>Un entier</returns>
  • public int Draw()
  • {
  • return this.Draw(0, 0);
  • }
  • /// <summary>
  • /// Dessine le Bitmap sur l'objet Graphics aux coordonnées spécifiées
  • /// </summary>
  • /// <param name="x">Distance X du bord gauche du Graphics</param>
  • /// <param name="y">Distance Y du bord haut du Graphics</param>
  • /// <returns>Un entier</returns>
  • public int Draw(int x, int y)
  • {
  • return GdipDrawCachedBitmap(this._pGraphicsfi, this._pCachedBitmap, x, y);
  • }
  • /// <summary>
  • /// Dessine le bitmap sur l'objet Graphics au coin haut-gauche spécifié par le Point
  • /// </summary>
  • /// <param name="p">Un objet Point qui désigne le coin haut-gauche où sera dessiné le Bitmap</param>
  • /// <returns>Un entier</returns>
  • public int Draw(Point p)
  • {
  • return this.Draw(p.X, p.Y);
  • }
  • /// <summary>
  • /// Libère les ressources utilisées par le CachedBitmap non managé.
  • /// </summary>
  • public void Delete()
  • {
  • GdipDeleteCachedBitmap(this._pCachedBitmap);
  • this._isLoaded = false;
  • }
  • }
  • }
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Reflection;

namespace ManagedCachedBitmap
{
    /// <summary>
    /// Wrapper pour les CachedBitmap non managés de GDI+
    /// </summary>
    public class ManagedCachedBitmap
    {
        [DllImport("gdiplus.dll")]
        public static extern int GdipCreateCachedBitmap(IntPtr pBitmap, IntPtr pGraphics, ref IntPtr pCachedBitmap);
        [DllImport("gdiplus.dll")]
        public static extern int GdipDrawCachedBitmap(IntPtr pGraphics, IntPtr pCachedBitmap, int x, int y);
        [DllImport("gdiplus.dll")]
        public static extern int GdipDeleteCachedBitmap(IntPtr pCachedBitmap);

        private Bitmap _cachedBitmap;
        private Graphics _graphics;
        private IntPtr _pCachedBitmap;
        private FieldInfo _Bitmapfi;
        private FieldInfo _Graphicsfi;
        private IntPtr _pBitmapfi;
        private IntPtr _pGraphicsfi;
        private Boolean _isLoaded = false;

        /// <summary>
        /// Constructeur.
        /// </summary>
        /// <param name="b">un objet Bitmap</param>
        /// <param name="g">un objet Graphics</param>
        public ManagedCachedBitmap(Bitmap b, Graphics g)
        {
            this.Init(b, g);
        }

        /// <summary>
        /// Destructeur
        /// </summary>
        ~ManagedCachedBitmap()
        {
            this.Delete();
        }

        /// <summary>
        /// Utilisé pour initialiser un CachedBitmap à partir d'un Graphics et d'un Bitmap
        /// </summary>
        /// <param name="b">un objet Bitmap</param>
        /// <param name="g">un objet Graphics</param>
        public void Init(Bitmap b, Graphics g)
        {
            if (_isLoaded) this.Delete();
            this._cachedBitmap = b;
            this._graphics = g;
            this._Bitmapfi = typeof(Bitmap).GetField("nativeImage", BindingFlags.Instance | BindingFlags.NonPublic);
            this._pBitmapfi = (IntPtr)this._Bitmapfi.GetValue(this._cachedBitmap);
            this._Graphicsfi = typeof(Graphics).GetField("nativeGraphics", BindingFlags.Instance | BindingFlags.NonPublic);
            this._pGraphicsfi = (IntPtr)this._Graphicsfi.GetValue(this._graphics);
            GdipCreateCachedBitmap(this._pBitmapfi, this._pGraphicsfi, ref this._pCachedBitmap);
            this._isLoaded = true;
        }

        /// <summary>
        /// Modifie seulement le Bitmap sans avoir à tout refaire (plus rapide que la méthode Init() ). Utile pour faire une animation par exemple.
        /// </summary>
        /// <param name="b">Un objet Bitmap</param>
        /// <returns></returns>
        /// <remarks>La mise à jour ne sera pas effectuée si la méthode</remarks>
        public Boolean InitBitmap(Bitmap b)
        {
            if (!_isLoaded) return false;
            this.Delete();
            this._cachedBitmap = b;
            this._Bitmapfi = typeof(Bitmap).GetField("nativeImage", BindingFlags.Instance | BindingFlags.NonPublic);
            this._pBitmapfi = (IntPtr)this._Bitmapfi.GetValue(this._cachedBitmap);
            GdipCreateCachedBitmap(this._pBitmapfi, this._pGraphicsfi, ref this._pCachedBitmap);
            this._isLoaded = true;
            return true;
        }

        /// <summary>
        /// Modifie seulement le Graphics où l'on dessinera le Bitmap (plus rapide que la méthode Init() ).
        /// </summary>
        /// <param name="g"></param>
        /// <returns></returns>
        public Boolean InitGraphics(Graphics g)
        {
            if (!_isLoaded) return false;
            this.Delete();
            this._graphics = g;
            this._Graphicsfi = typeof(Graphics).GetField("nativeGraphics", BindingFlags.Instance | BindingFlags.NonPublic);
            this._pGraphicsfi = (IntPtr)this._Graphicsfi.GetValue(this._graphics);
            GdipCreateCachedBitmap(this._pBitmapfi, this._pGraphicsfi, ref this._pCachedBitmap);
            this._isLoaded = true;
            return true;
        }

        /// <summary>
        /// Définit ou renvoie le Bitmap utilisé
        /// </summary>
        public Bitmap Bitmap
        {
            get
            {
                return _cachedBitmap;
            }
            set
            {
                this._cachedBitmap = value;
                this.InitBitmap(this._cachedBitmap);
            }
        }

        /// <summary>
        /// Définit ou renvoie le Graphics utilisé
        /// </summary>
        public Graphics Graphics
        {
            get
            {
                return _graphics;
            }
            set
            {
                this._graphics = value;
                this.InitGraphics(this._graphics);
            }
        }

        /// <summary>
        /// Vrai si l'initialisation du CachedBitmap s'est déroulée correctement
        /// </summary>
        public bool IsLoaded
        {
            get
            {
                return _isLoaded;
            }
        }

        /// <summary>
        /// Dessine le Bitmap sur l'objet Graphics aux coordonnées (0 ; 0)
        /// </summary>
        /// <returns>Un entier</returns>
        public int Draw()
        {
            return this.Draw(0, 0);
        }

        /// <summary>
        /// Dessine le Bitmap sur l'objet Graphics aux coordonnées spécifiées
        /// </summary>
        /// <param name="x">Distance X du bord gauche du Graphics</param>
        /// <param name="y">Distance Y du bord haut du Graphics</param>
        /// <returns>Un entier</returns>
        public int Draw(int x, int y)
        {
            return GdipDrawCachedBitmap(this._pGraphicsfi, this._pCachedBitmap, x, y);
        }

        /// <summary>
        /// Dessine le bitmap sur l'objet Graphics au coin haut-gauche spécifié par le Point
        /// </summary>
        /// <param name="p">Un objet Point qui désigne le coin haut-gauche où sera dessiné le Bitmap</param>
        /// <returns>Un entier</returns>
        public int Draw(Point p)
        {
            return this.Draw(p.X, p.Y);
        }

        /// <summary>
        /// Libère les ressources utilisées par le CachedBitmap non managé.
        /// </summary>
        public void Delete()
        {
            GdipDeleteCachedBitmap(this._pCachedBitmap);
            this._isLoaded = false;
        }

    }
}

Conclusion

Après quelques tests, il apparait que la méthode des CachedBitmap est rapide, mais à peu près autant que la méthode managée disponible en .NET 2.0 Graphics.DrawImageUnscaled(). L'utilité de ma source est donc sans doute limitée mais en outre la source en elle-même est intéressante je pense.
Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

27 mars 2008 12:22:21 :
Petit bug.
  • signaler à un administrateur
    Commentaire de Kevin.Ory le 29/03/2008 19:15:09

    Salut,

    Excellent boulot ça, merci :)

    C'est effectivement ce que je recherchais (je crois, je n'ai pas encore analysé ton code en détails), mais j'avais abandonné l'idée d'essayer d'améliorer mon programme .NET 2, et je suis passé à .NET 3.5. As-tu déjà essayé WPF? C'est assez magnifique, ça s'utilise un peu comme DirectX (logique, puisque c'est du DirectX), et à évidement des performances incomparable avec GDI32 (Plusieurs images de haute résolution avec mouvement et zoom temps réel sans problèmes).
    Mais j'ai juste essayé, je ne consacre plus bcp de temps à la prog ces temps, mais vais bien m'y remettre un jour :)

    Pour ce qui est ton code, comme tu le dis il est très intéressant car nous permet de comprendre comment wrapper un objet non managé, mais dommage que les performances ne soit pas à la hauteur de ce que j'attendais. Je vais tester tout ça en détail un de ces prochains jours (et je noterai après ^^).

    Encore merci, et bonne continuation à toi..


Ajouter un commentaire

Appels d'offres

Pub



CalendriCode

Mai 2008
LMMJVSD
   1234
567891011
12131415161718
19202122232425
262728293031 

VS Express FR Gratuit !

VS Express en français et 100% gratuit !