GDI+ et ASP.Net : la génération d'images

N'hésitez pas à commenter cet article ! Commentez Donner une note à l'article (5)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

Introduction

La génération d'images peut avoir bien des applications. L'une des plus connues est certainement le fait de les utiliser pour sécuriser le remplissage d'un formulaire, ainsi cela permet d'empêcher l'automatisation de ce processus par des robots logiciel. Dans cet article, nous verrons comment générer des images grâce au Framework, avec un aperçu des possibilités offertes.

1. Génération d'une image contenant du texte

Nous allons, dans un premier temps, voir comment générer des images grâce à GDI+ et l'ASP.Net. Il s'agira d'une image simple contenant du texte. Nous allons utiliser, pour cela, un ensemble de classes fournies par le Framework. Ces classes sont contenues dans l'espace de noms System.Drawing et System.Drawing.Imaging.

1.1. Image sauvegardée sur le disque dur

Pour générer une image, plusieurs étapes sont nécessaires, et il y a un certain nombre d'objets à instancier. Cela reste simple, et surtout logique, donc pas d'inquiétude !

Voici le code complet permettant de générer une image et de l'enregistrer sur le disque dur du serveur.

Génération d'image vers le disque dur :
Sélectionnez

Sub generationImageVersDisque(ByVal monTexte As String)

        ' Instanciation d'un objet Bitmap qui va jouer, en quelque sorte, le rôle de conteneur.
        ' On passe au constructeur les dimensions en pixels que l'on souhaite (largeur, hauteur)
        Dim monBitmap As Bitmap = New Bitmap(700, 80)


        ' Création d'un objet Graphics qui va être notre surface de dessin, on l'associe
        ' à notre objet Bitmap grâce à la méthode FromImage
        Dim monGraphic As Graphics = Graphics.FromImage(monBitmap)


        ' Instanciation de deux objets Brush qui vont nous permettre, respectivement,
        ' de "peindre" le fond, puis de "dessiner" le texte par dessus. Nous leur
        ' passons la couleur que l'on souhaite leur donner
        Dim monPinceau As New SolidBrush(Color.Tomato)
        Dim monStylo As New SolidBrush(Color.Yellow)


        ' Ici nous nous créons un rectangle de la taille de notre surface de dessin avec
        ' l'objet Brush.
        monGraphic.FillRectangle(monPinceau, 0, 0, 700, 80)


        ' Objet Font qui contient la police et ses caractéristiques
        Dim maPolice As New Font("Arial", 35, FontStyle.Regular)


        ' Structure PointF qui est un ensemble de 2 coordonnées pour le début du texte
        ' sur la surface de dessin.
        Dim mesCoor As New PointF(5.0F, 5.0F)


        ' Rendu du texte : ici nous sommes en qualité optimale.
        ' Plus de détails sur le sujet dans la suite de ce tutoriel
        monGraphic.TextRenderingHint = Text.TextRenderingHint.ClearTypeGridFit


        ' "Ecriture" du texte sur la surface de dessin, en paramètres, on passe, 
        ' dans l'ordre, le texte, la police, le pinceau, et l'emplacement.
        monGraphic.DrawString(monTexte, maPolice, monStylo, mesCoor)


        ' Enregistrement à la racine de l'application le fichier généré
        monBitmap.Save(Server.MapPath("monImage.jpg"), ImageFormat.Jpeg)


        ' Ce code crée un lien sur votre page pour que vous puissiez vérifier le résultat,
        ' mais il n'est pas nécessaire pour la création de l'image elle-même.
        Response.Write("<a target=""_parent"" href=""monImage.jpg"">Votre image</a>")


    End Sub

Quelques explications :

Objet Bitmap :

Il s'agit, en quelque sorte, d'un conteneur dans lequel nous placerons notre image. Nous passons au constructeur les dimensions en pixels de celui-ci; en premier la largueur, puis la hauteur. Il existe une douzaine de surcharges différentes, mais ici nous avions seulement besoin de spécifier la taille de notre Bitmap.

Objet Graphics :

L'objet Graphics va être notre surface de dessin. La classe Graphics fournit, entre autre, des méthodes pour dessiner des formes (rectangles, lignes…). Nous allons créer un objet Graphics en lui passant en paramètre notre objet Bitmap instancié à l'étape précédente.

Objets Brush :

Nous avons créé des instances d'objets nous permettant de "dessiner" notre image. Nous utilisons deux objets " pinceaux ", un pour colorer le fond de notre image, puis un autre pour écrire (ou plutôt dessiner) le texte par-dessus.

Méthode FillRectangle (classe Graphics) :

Cette méthode crée un rectangle à partir du point 0,0 sur la totalité de notre surface de dessin, qui je le rappelle fait 700 x 100 pixels.

Méthode DrawString (classe Graphics) :

La méthode DrawString permet de dessiner une chaîne de caractères sur un objet Graphics. Cette méthode admet plusieurs surcharges, ce qui nous offre diverses possibilités.

Méthode Save (classe Bitmap) :

La méthode Save permet d'enregistrer notre image dans un fichier, et cela au format que l'on souhaite. Les principaux formats supportés sont : Bmp, Gif, Icon, Jpeg, Png et Tiff. On passe à cette méthode en premier le chemin de stockage, puis le format du fichier à enregistrer.

Remarque : le compte ASP.Net doit avoir le droit d'écriture sur l'emplacement où va être stocké le fichier. En cas de droits insuffisants, une exception sera levée.

1.2. Transfert direct de l'image de la mémoire à la page ASPX

Le fait d'enregistrer une image sur le disque dur, après l'avoir générée, peut, selon les cas, être une opération inutile, lente, et consommatrice de ressources. Donc si l'enregistrement sur le disque de cette image n'est pas indispensable, vous pouvez l'envoyer directement vers le client, depuis la mémoire. Pour cela, il suffit simplement de modifier la dernière étape de notre génération. Plus précisément, au lieu d'enregistrer l'image avec le code suivant :

 
Sélectionnez

' Enregistrement à la racine de l'application le fichier généré
monBitmap.Save(Server.MapPath("monImage.jpg"), ImageFormat.Jpeg

Il faut l'envoyer au client avec ce code :

 
Sélectionnez

Response.ContentType = "image/jpeg"
monBitmap.Save(Response.OutputStream, ImageFormat.Jpeg)

Comme vous pouvez le voir ce n'est vraiment pas sorcier !

1.3. Le rendu des textes

Le rendu du texte va faire que votre image sera de bonne qualité, ou de moins bonne, mais avec un volume moins important. Il existe 6 rendus différents proposés par le Framework, ces 6 rendus sont spécifiques au texte contenu dans une image. Tout cela est intégré dans l'espace de noms System.Drawing.Text . Pour le rendu de l'image, ici nous ne l'étudierons pas (notre image présentant un fond uni…), il faut utiliser QualityMode se trouvant dans l'espace de noms System.Drawing.Drawing2D .

Voici la présentation de ces rendus, leur description est issue du MSDN :

Membre Description
AntiAlias Spécifie que chaque caractère est dessiné en utilisant sa bitmap de glyphe non crénelée, sans affinage. La qualité est meilleure en raison de l'anticrénelage. L'affinage étant désactivé, les différences de largeur du jambage risquent d'être plus visibles.
AntiAliasGridFit Spécifie que chaque caractère est dessiné en utilisant sa bitmap de glyphe non crénelée, avec affinage. La qualité est sensiblement meilleure en raison de l'anticrénelage, mais au détriment de la vitesse.
ClearTypeGridFit Spécifie que chaque caractère est dessiné en utilisant sa bitmap de glyphe ClearType, avec affinage. Il s'agit de la qualité optimale. Permet de tirer parti des fonctionnalités des polices ClearType.
SingleBitPerPixel Spécifie que chaque caractère est dessiné en utilisant sa bitmap de glyphe. L'affinage n'est pas utilisé.
SingleBitPerPixelGridFit Spécifie que chaque caractère est dessiné en utilisant sa bitmap de glyphe. L'affinage est utilisé pour améliorer l'apparence du jambage et de la courbure des caractères.
SystemDefault Spécifie que chaque caractère est dessiné en utilisant sa bitmap de glyphe, avec l'affinage de rendu par défaut utilisé par le système. Le texte sera dessiné en utilisant les paramètres de lissage de police sélectionnés par l'utilisateur sur le système.

Vous trouverez en bas de page le lien relatif à cette documentation.

Pour appliquer le rendu à notre texte, se trouvant sur notre surface monGraphic, il faut procéder de la manière suivante :

 
Sélectionnez

monGraphic.TextRenderingHint = Text.TextRenderingHint.ClearTypeGridFit

Voilà, rien de bien complexe, une fois de plus, tout est pris en charge par le Framework.

2. Différents pinceaux proposés par GDI+

2.1. SolidBrush

Il s'agit du pinceau "de base" qui permet de remplir des formes, telles que les carrés, rectangles, ellipses… avec une couleur unie. Cette classe se trouve dans le namespace System.Drawing, et comme tous les autres pinceaux, elle hérite de la classe Brush.

2.2. Linear et Path Gradient Brush

LinearGradientBrush : c'est un pinceau permettant de faire un dégradé linéaire de couleurs. Il est possible d'employer deux ou plusieurs couleurs et, également, de choisir le mode de mélange des couleurs grâce à des méthodes spécifiques. Ainsi, les résultats possibles sont très nombreux.

PathGradientBrush : ce pinceau permet aussi de réaliser des dégradés linéaires de couleurs, mais son fonctionnement est un peu plus complexe que le précédent. Il permet notamment de créer des dégradés de couleurs partant du centre de l'image.

2.3. HatchBrush

Ce pinceau permet de définir un "hachurage" de l'image avec une couleur de premier et d'arrière plan. L'hachurage de l'image est contenu dans la propriété HachStyle, il en existe une multitude. Je vous renvoie au MSDN pour de plus amples informations.

2.4. TextureBrush

Ce pinceau est un peu différent dans le sens où il utilise un fichier image pour remplir la surface concernée. Il permet donc d'utiliser des textures existantes.

Voilà pour ce tour rapide des principaux types de pinceaux. Ils possèdent tous de nombreuses méthodes et propriétés permettant d'obtenir un résultat très fin, il ne faut donc pas hésiter à se rapporter à leur documentation.

3. Génération d'une image contenant un texte aléatoire

3.1. La méthode

Nous allons ici créer une image de manière aléatoire, cela signifie que le texte qu'elle va contenir sera écrit aléatoirement, de manière à ce qu'il ne soit pas possible de prédire quel sera ce texte. En plus, nous allons définir, de manière aléatoire, quelle sera la couleur du fond. Il serait possible d'avoir un fond non uni, présentant une surface irrégulière, mais ce n'est pas ici le sujet. Nous nous contenterons d'un texte aléatoire sur fond uni. Mais il est important de préciser, que sans grande difficulté, il serait possible d'avoir un texte de taille et de casse variable, ce qui pourrait être un gage de sécurité supplémentaire face aux "robots logiciels" qui parfois arrivent à "lire" les images contenues dans les processus d'inscription sur les forums, ou autres.

Notre façon de procéder va être très simple, et ne va rien inventer. Nous allons simplement nous appuyer sur le Framework et sa classe Random qui offre des méthodes pour obtenir des chiffres de manière aléatoire.

Tout d'abord, nous allons instancier un objet Random, puis avec sa méthode Next nous allons déterminer la couleur du fond. Ensuite nous allons procéder de même pour composer la chaîne de caractères à partir d'un tableau contenant les 26 lettres de l'alphabet, ainsi que les chiffres 1 à 9. La classe Random s'appuyant sur une valeur initiale pour générer des nombres, nous utiliserons une valeur relative au temps pour changer ainsi le mode de génération à chaque affichage d'une image. Ainsi, à chaque instanciation de la classe Random, nous lui passerons "DateTime.Now.Millisecond" qui retourne un entier.

Rien ne sert de détailler plus les explications, la lecture du code commenté vous permettra de voir, précisément, quelle est la façon de procéder.

Avertissement : après quelques tests, Random ne s'avère pas être totalement aléatoire... En effet, certaines chaînes reviennent tous les 20 à 30 essais, ce n'est pas un problème en soit, pour l'utilisation que l'on veut en faire, mais je tenais quand même à le signaler.

3.2. Le code commenté

Génération d'une image contenant un texte aléatoire
Sélectionnez

    Sub generationImageAleatoire(ByVal nombreCaracteres As Integer)

        ' Création du conteneur de notre image
        Dim monBitmap As Bitmap = New Bitmap(185, 50)
        Dim monGraphic As Graphics = Graphics.FromImage(monBitmap)


        ' Choix aléatoire de la couleur du fond. RVB limité à 200 pour que
        ' le fond ne soit pas trop clair (car écriture blanche)
        Dim nombreAleatoire As Random = New Random(DateTime.Now.Millisecond)
        Dim r, v, b As Integer
        r = nombreAleatoire.Next(0, 200)
        v = nombreAleatoire.Next(0, 200)
        b = nombreAleatoire.Next(0, 200)

        ' Coloration du fond
        Dim monPinceau As New SolidBrush(Color.FromArgb(r, v, b))
        monGraphic.FillRectangle(monPinceau, 0, 0, 185, 50)

        ' Création de la Font pour écrire le texte
        Dim maFont As Font = New Font("Arial", 25, FontStyle.Regular)

        ' Création du "stylo" qui va nous permettre d'écrire le texte
        Dim monStylo As New SolidBrush(Color.White)

        ' Structure PointF qui est un ensemble de 2 coordonnées pour le début du texte
        ' sur la surface de dessin.
        Dim mesCoor As New PointF(5.0F, 5.0F)


        ' Liste des caractères composant la chaîne aléatoire
        Dim liste() As String = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", _
                                "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", _
                                "W", "X", "Y", "Z", "1", "2", "3", "4", "5", "6", "7", "8", "9"}

        ' Variable qui va contenir le texte
        Dim monTexte As StringBuilder = New StringBuilder

        ' Création aléatoire du texte
        Dim i As Integer = 0
        While i < nombreCaracteres
            monTexte = monTexte.Append(liste(nombreAleatoire.Next(0, 34)))
            i += 1
        End While

        ' Détermination du rendu du texte dans l'image
        monGraphic.TextRenderingHint = Text.TextRenderingHint.ClearTypeGridFit

        ' La chaîne est "dessinée" sur l'image
        monGraphic.DrawString(monTexte.ToString, maFont, monStylo, mesCoor)

        ' Affichage de l'image sur la page
        Response.ContentType = "image/jpeg"
        monBitmap.Save(Response.OutputStream, ImageFormat.Jpeg)

    End Sub

Conclusion

J'espère qu'au travers de ce tour d'horizon rapide de GDI+ avec ASP.Net, vous aurez pu entrevoir les possibilités qui s'offrent à vous ! En quelques lignes de codes, nous avons pu générer des images (certes basiques, mais des images quand même ! ). Une fois de plus le Framework nous a fourni les briques essentielles, sans que l'on ait à ré-inventer la roue ! En espérant vous avoir intéressé, je vous donne rendez vous dans un prochain tutoriel.

Ressources

Les rendus de texte
La classe Brush

Merci beaucoup à Piotrek, Bestiol et Freegreg pour la relecture de ce tutoriel.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2004 Ronald VASSEUR. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.