Wrapper .net 2.0 pour les cachedbitmap de gdi+

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 / Exemple :


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.

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.