Utiliser GDI+ et ASP .net! Mais pourquoi donc?
Parfois il est plus simple d’afficher une image que de taper le code HTML permettant un rendu bien précis. C’est la cas par exemple quand on souhaite afficher des graphiques… la moindre modification de la mise en page se transforme en cauchemar. C’est alors qu’arrive l’ami GDI sur son beau cheval blanc. Pour ceux qui ne connaitrait pas GDI, faisons simple : il s’agit de la librairie utilisé par windows pour faire la plus part de ses rendu visuels, interfaces winform et images.
Cela faisait quelques temps que je n’avais pas fait ce genre de choses, alors voici un petit exemple de ce qui peut être fait pour afficher une image représentant un jauge.
Mais avant de commencer, voici un échantillons de ce qui peut être obtenu avec le code suivant.

Pour commencer, GDI devant écrire dans la Stream de l’objet Response si on l’utilise tel quel, notre sortie comportera le binaire d’une image et notre navigateur n’affichera que celle-ci (un peu comme quand on ecrit un fichier sur la Stream de Response). Donc l’idée est d’utiliser un Handler qui se chargerai de retourner un Response utiliser comme source (src) d’une balise image (img). Pour y arriver j’écrit donc une classe implémentant l’interface IHttpHnadler et je change mon fichier de configuration afin qu’il prenne en compte ce Handler.
<system.web>
<authorization>
<deny users="*"/>
</authorization>
<httpHandlers>
<add verb="GET"
path="Jauge.axd"
type="MonNameSpace.Jauge, MonNameSpace"
/>
</httpHandlers>
</system.web>
<location path="Jauge.axd">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>
J’en ai profiter pour ajouter les droits d’accès au Handler, afin dans le cas d’une authentification Forms de m’assurer que l’accès à celui-ci est possible.
Note : Dans le cas où vous utiliseriez IIS7 sachez que ce dernier (pat défaut) préfèrera que vous créiez une fichier (jauge.axd) qu’un handler dans le fichier de config.
Notre jauge serra utilisable sous la forme d’un control dont l’utilisation via ASP .net se ferra sous la forme suivante
<%@ Register Assembly="MonNameSpace" Namespace="MonNameSpace" TagPrefix="ctrl" %> <ctrl:Jauge runat="server" ID="MaJaugeQueJAimeBeaucoup" Valeur="2000" Valeurtotal="8000"></ctrl:Jauge>
Passons maintenant aux soses sérieuses, le code GDI ;)
Vb
Namespace MonNameSpace
<ToolboxData("<{0}:Jauge runat=server></{0}:Jauge>")>
Public Class Jauge
Inherits WebControl
Implements IHttpHandler
Private _valeur As Int32
Private _valeurTotale As Int32
''' <summary>
''' Valeur de la jauge
''' </summary>
Public Property Valeur As Int32
Get
Return Me._valeur
End Get
Set(ByVal value As Int32)
Me._valeur = value
End Set
End property
''' <summary>
''' Valeur maximum de la jauge
''' </summary>
Public Int32 ValeurTotale
Get
return Me._valeurTotale
End Get
Set(ByVal value As Int32)
Me._valeurTotale = value
End Set
End property
''' <summary>
''' Rendu du control
''' </summary>
''' <param name="writer"></param>
Protected Override Sub Render(ByVal writer As HtmlTextWriter)
writer.WriteLine( _
String.Format( _
"<img src='Jauge.axd?value={0}&max={1}' alt='Jauge' border='0' />", _
Me._valeur, _
Me._valeurTotale))
End Sub
Private Const _width As Int32 = 600
Private Const _height As Int32 = 17
Private Const _margeInterneJauge As Int32 = 2
Private Const _graduationTop As Int32 = _height
Private Const _graduationHeight As Int32 = 4
Private Const _margeBord As Int32 = 40
Public Property IsReusable As Boolean ' IHttpHandler
Get
Return False
End Get
End Property
Public Sub ProcessRequest(ByVal context As HttpContext) ' IHttpHandler
' Largeur de l'image
Dim value As Int32 = Convert.ToInt32(context.Request("value"))
Dim max As Int32 = Convert.ToInt32(context.Request("max"))
' Zone de déssin
Dim bmp As New Bitmap(_width, _height + 40)
' Control de dessin
Dim g As New Graphics.FromImage(bmp)
' Progression de la barre
Dim rectJauge As New Rectangle( _
_margeBord, _
0, _
_width - 1 - _margeBord*2, _
_height - 1)
Dim progress As Int32 = (value * rectJauge.Width) / max
Dim rectProgess As New Rectangle( _
rectJauge.X+ _margeInterneJauge, _
rectJauge.Y +_margeInterneJauge, _
progress - (_margeInterneJauge * 2), _
rectJauge.Height - _margeInterneJauge * 2)
' Fond
g.Clear(Color.White)
' Jauge
g.FillRectangle(Brushes.Gray, rectJauge)
g.DrawRectangle(Pens.Black, rectJauge)
' Remplire la jauge
Me.PaintBackAeroGlass(g, rectProgess, System.Drawing.Color.LawnGreen, Nothing)
' Graduations
DrawGraduation(g, rectJauge.X, 0)
DrawGraduation(g, rectJauge.X + rectJauge.Width / 4, max / 4)
DrawGraduation(g, rectJauge.X + rectJauge.Width / 2, max / 2)
DrawGraduation(g, rectJauge.X + rectJauge.Width * 3 / 4, max * 3 / 4)
DrawGraduation(g, rectJauge.X + rectJauge.Width, max)
bmp.Save( _
context.Response.OutputStream, _
System.Drawing.Imaging.ImageFormat.Jpeg)
End Sub
''' <summary>
''' Dessiner une graduation
''' </summary>
''' <param name="g"></param>
''' <param name="x"></param>
''' <param name="value"></param>
Private Sub DrawGraduation(ByVal g As Graphics, ByVal x As Int32,ByVal value As Int32)
g.DrawLine(Pens.Black, x, _graduationTop, x, _graduationTop + _graduationHeight)
g.DrawString( _
value.ToString(), _
New Font("Verdana", 12), _
Brushes.Black, _
x, _
_graduationTop + _graduationHeight + 10, _
New StringFormat With { _
.Alignment = StringAlignment.Center, _
.LineAlignment = StringAlignment.Center })
End Sub
''' <summary>
''' Fond type Aéro glass
''' </summary>
''' <param name="vG"></param>
''' <param name="vRect"></param>
''' <param name="vColor"></param>
''' <param name="vMasque"></param>
Public Sub PaintBackAeroGlass(ByVal graphics As Graphics,ByVal zone As Rectangle, ByVal couleur As Color, ByVal masque As GraphicsPath)
Dim Int_Heiht As Int32
Dim rect1, rect2 As Rectangle
Dim brush1 As LinearGradientBrush = Nothing
Dim brush2 As LinearGradientBrush = Nothing
Try
Int_Heiht = Convert.ToInt32(zone.Height / 2)
rect1 = New Rectangle(zone.X, zone.Y, zone.Width, Int_Heiht)
rect2 = New Rectangle(zone.X, zone.Y + Int_Heiht, zone.Width, zone.Height - Int_Heiht)
brush1 = New LinearGradientBrush( _
rect1, _
Color.FromArgb(50, couleur), _
Color.FromArgb(160, couleur), _
LinearGradientMode.Vertical)
brush2 = New LinearGradientBrush( _
rect2, _
Color.FromArgb(190, couleur), _
Color.FromArgb(210, couleur), _
LinearGradientMode.Vertical)
' Paint des 2 rect
If masque Is Nothing Then
' sans masque
graphics.FillRectangle(new SolidBrush(Color.White), zone)
graphics.FillRectangle(brush1, rect1)
graphics.FillRectangle(brush2, rect2)
Else
Region r = null
Try
' Avec masque
graphics.FillPath(New SolidBrush(Color.White), masque)
r = New Region(masque)
r.Intersect(rect1)
graphics.FillRegion(brush1, r)
r = New Region(masque)
r.Intersect(rect2)
graphics.FillRegion(brush2, r)
Finally
//Libération mémoire
if (r != null) r.Dispose();
r = null;
End Try
End If
Catch
Finally
if brush1 IsNot Nothing Then brush1.Dispose()
brush1 = Nothing
if brush2 IsNot Nothing Then brush2.Dispose()
brush2 = Nothing
End Try
End Sub
End Namespace
C#
namespace MonNameSpace
{
[ToolboxData("<{0}:Jauge runat=server></{0}:Jauge>")]
public class Jauge : WebControl, IHttpHandler
{
private Int32 _valeur;
private Int32 _valeurTotale;
/// <summary>
/// Valeur de la jauge
/// </summary>
public Int32 Valeur
{
get { return this._valeur; }
set { this._valeur = value; }
}
/// <summary>
/// Valeur maximum de la jauge
/// </summary>
public Int32 ValeurTotale
{
get { return this._valeurTotale; }
set { this._valeurTotale = value; }
}
/// <summary>
/// Rendu du control
/// </summary>
/// <param name="writer"></param>
protected override void Render(HtmlTextWriter writer)
{
writer.WriteLine(
String.Format(
@"<img src='Jauge.axd?value={0}&max={1}' alt='Jauge' border='0' />",
this._valeur ,
this._valeurTotale));
}
private const Int32 _width = 600;
private const Int32 _height = 17;
private const Int32 _margeInterneJauge = 2;
private const Int32 _graduationTop = _height;
private const Int32 _graduationHeight = 4;
private const Int32 _margeBord = 40;
public Boolean IsReusable //IHttpHandler
{
get { return false; }
}
public void ProcessRequest(HttpContext context) //IHttpHandler
{
// Largeur de l'image
Int32 value = Convert.ToInt32(context.Request["value"]);
Int32 max = Convert.ToInt32(context.Request["max"]);
// Zone de déssin
Bitmap bmp = new Bitmap(_width, _height + 40);
// Control de dessin
Graphics g = Graphics.FromImage(bmp);
// Progression de la barre
Rectangle rectJauge = new Rectangle(
_margeBord,
0,
_width - 1 - _margeBord*2,
_height - 1);
Int32 progress = (value * rectJauge.Width) / max;
Rectangle rectProgess = new Rectangle(
rectJauge.X+ _margeInterneJauge,
rectJauge.Y +_margeInterneJauge,
progress - (_margeInterneJauge * 2),
rectJauge.Height - _margeInterneJauge * 2);
// Fond
g.Clear(Color.White);
// Jauge
g.FillRectangle(Brushes.Gray, rectJauge);
g.DrawRectangle(Pens.Black, rectJauge);
// Remplire la jauge
this.PaintBackAeroGlass(g, rectProgess, System.Drawing.Color.LawnGreen, null);
// Graduations
DrawGraduation(g, rectJauge.X, 0);
DrawGraduation(g, rectJauge.X + rectJauge.Width / 4, max / 4);
DrawGraduation(g, rectJauge.X + rectJauge.Width / 2, max / 2);
DrawGraduation(g, rectJauge.X + rectJauge.Width * 3 / 4, max * 3 / 4);
DrawGraduation(g, rectJauge.X + rectJauge.Width, max);
bmp.Save(
context.Response.OutputStream,
System.Drawing.Imaging.ImageFormat.Jpeg);
}
/// <summary>
/// Dessiner une graduation
/// </summary>
/// <param name="g"></param>
/// <param name="x"></param>
/// <param name="value"></param>
private void DrawGraduation(Graphics g, Int32 x,Int32 value)
{
g.DrawLine(Pens.Black, x, _graduationTop, x, _graduationTop + _graduationHeight);
g.DrawString(
value.ToString(),
new Font("Verdana", 12),
Brushes.Black,
x,
_graduationTop + _graduationHeight + 10,
new StringFormat() {
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center });
}
/// <summary>
/// Font type Aéro glass
/// </summary>
/// <param name="vG"></param>
/// <param name="vRect"></param>
/// <param name="vColor"></param>
/// <param name="vMasque"></param>
private void PaintBackAeroGlass(Graphics graphics, Rectangle zone, Color couleur, GraphicsPath masque)
{
Int32 Int_Heiht;
Rectangle rect1, rect2;
LinearGradientBrush
brush1 = null,
brush2 = null;
try
{
Int_Heiht = Convert.ToInt32(zone.Height / 2);
rect1 = new Rectangle(zone.X, zone.Y, zone.Width, Int_Heiht);
rect2 = new Rectangle(zone.X, zone.Y + Int_Heiht, zone.Width, zone.Height - Int_Heiht);
brush1 = new LinearGradientBrush(
rect1,
Color.FromArgb(50, couleur),
Color.FromArgb(160, couleur),
LinearGradientMode.Vertical);
brush2 = new LinearGradientBrush(
rect2,
Color.FromArgb(190, couleur),
Color.FromArgb(210, couleur),
LinearGradientMode.Vertical);
//Paint des 2 rect
if (masque == null)
{
//sans masque
graphics.FillRectangle(new SolidBrush(Color.White), zone);
graphics.FillRectangle(brush1, rect1);
graphics.FillRectangle(brush2, rect2);
}
else
{
Region r = null;
try
{
//Avec masque
graphics.FillPath(new SolidBrush(Color.White), masque);
r = new Region(masque);
r.Intersect(rect1);
graphics.FillRegion(brush1, r);
r = new Region(masque);
r.Intersect(rect2);
graphics.FillRegion(brush2, r);
}
finally
{
//Libération mémoire
if (r != null) r.Dispose();
r = null;
}
}
}
catch { }
finally
{
if (brush1 != null) brush1.Dispose();
brush1 = null;
if (brush2 != null) brush2.Dispose();
brush2 = null;
}
}
}
}
