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 :
Sub generationImageVersDisque(ByVal monTexte AsString)
' 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 FromImageDim 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 donnerDim monPinceau AsNew SolidBrush(Color.Tomato)
Dim monStylo AsNew 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éristiquesDim maPolice AsNew 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 AsNew 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>")
EndSub
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 :
' Enregistrement à la racine de l'application le fichier généré
monBitmap.Save(Server.MapPath("monImage.jpg"), 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 :
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
Sub generationImageAleatoire(ByVal nombreCaracteres AsInteger)
' Création du conteneur de notre imageDim 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 AsInteger
r = nombreAleatoire.Next(0, 200)
v = nombreAleatoire.Next(0, 200)
b = nombreAleatoire.Next(0, 200)
' Coloration du fondDim monPinceau AsNew SolidBrush(Color.FromArgb(r, v, b))
monGraphic.FillRectangle(monPinceau, 0, 0, 185, 50)
' Création de la Font pour écrire le texteDim maFont As Font = New Font("Arial", 25, FontStyle.Regular)
' Création du "stylo" qui va nous permettre d'écrire le texteDim monStylo AsNew 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 AsNew PointF(5.0F, 5.0F)
' Liste des caractères composant la chaîne aléatoireDim liste() AsString = {"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 texteDim monTexte As StringBuilder = New StringBuilder
' Création aléatoire du texteDim i AsInteger = 0
While i < nombreCaracteres
monTexte = monTexte.Append(liste(nombreAleatoire.Next(0, 34)))
i += 1
EndWhile ' 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)
EndSub
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.