.NET : Génération d’une image à la volée

I believe I can (make an image on the) flyyyyyyy !

Imaginons qu’on veuille afficher une image qui changerait d’aspect à chaque chargement de page (graphiques, clavier virtuel pour l’authentification…). Il ne serait pas pratique de stocker ces images temporaires côté serveur (il faudrait être sûr de donner un nom unique aux images pour éviter les conflits par exemple).

La solution qui suit permet d’éviter de stocker des images sur le serveur. On va créer une page ASPX qui retourne un flux de type MIME « image/*** ».

Dans la page qui affichera l’image générée, il faut une balise de la sorte :

<img src="GenerateurImage.aspx" alt="" />

La page GenerateurImage.aspx ne contient rien (ou le minimum).
Tout se passe dans la procédure page_load du code-behind (
GenerateurImage.aspx.cs) :

public void Page_Load(object sender, System.EventArgs e)
{

// On peut partir d'une bitmap existante, ou en générer une nouvelle :

           Bitmap oBit = new Bitmap(???);
Graphics g =
Graphics.FromImage(oBit)


// Ici on modifie l'image avec toutes les méthodes offertes par la classe Graphics.
// On pourrait éventuellement utiliser des paramètres de la requête (ID=...)
pour rendre la chose encore plus dynamique !

// On change le type de flux de sortie
Response.ContentType = « image/jpeg »;

// On encode (compression)
ImageCodecInfo myImageCodecInfo;
Encoder myEncoder;
EncoderParameter myEncoderParameter;
EncoderParameters myEncoderParameters;

myImageCodecInfo = GetEncoderInfo(« image/jpeg »);
myEncoder = Encoder.Quality;

myEncoderParameters = new EncoderParameters(1);

// Niveau d’encodage élévé.
myEncoderParameter = new EncoderParameter(myEncoder, 100L);
myEncoderParameters.Param[0] = myEncoderParameter;
oBit.Save(Response.OutputStream, myImageCodecInfo, myEncoderParameters);

oBit.Dispose();

// Pas de cache pour cette page.
Response.CacheControl = « no-cache »;
Response.AddHeader(« Pragma », « no-cache »);
Response.Expires = -1;
}

En bonus, la fonction qui ramène le codec :

        private static ImageCodecInfo GetEncoderInfo(String mimeType)
{
int j;
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for (j = 0; j < encoders.Length; ++j)
{
if (encoders[j].MimeType == mimeType)
return encoders[j];
}
return ';
}

C# : Exécuter un batch et récupérer la sortie.


private int Run_Batch(string sBatchPath, string sBatchName, string sArgs)
{

	// Code retour du batch
    int iExitCode = 0;

    // Chemin complet du batch
    string sBatchFullPath = sBatchPath + "\" + sBatchName;

    // Configuration du batch (chemin, arguments, sorties...)
    ProcessStartInfo processInfo = new ProcessStartInfo(sBatchFullPath);
    processInfo.CreateNoWindow = true;
    processInfo.Arguments = sArgs;
    processInfo.RedirectStandardOutput = true;
    processInfo.RedirectStandardError = true;
    processInfo.UseShellExecute = false;

    // Process en soi
    Process pBatch = new Process();

    // Redirection de la sortie vers une fonction
    pBatch.OutputDataReceived += new DataReceivedEventHandler(pBatch_OutputDataReceived);
    pBatch.StartInfo = processInfo;
    pBatch.EnableRaisingEvents = true;

    // Démarrage du batch + lecture des sorties.
    pBatch.Start();
    pBatch.BeginOutputReadLine();
    pBatch.BeginErrorReadLine();

    // Synchronisation
    pBatch.WaitForExit();
    iExitCode = pBatch.ExitCode;

    // Fermeture
    pBatch.Close();

    return iExitCode;
}

protected void pBatch_OutputDataReceived(Object sender, DataReceivedEventArgs e)
{
    System.Console.Write(e.Data);
}

C# : Créer rapidement un événement

Fiche mémo pour créer rapidement un événement lancé d’une classe, et abonnement à cet event.

Etapes de création d’un événement customisé complet (C#):

  • 1- DANS LA CLASSE SOULEVANT L’EVENEMENT
  • Delegate :
    public delegate void MonHandler(object sender, MonEventArgs e);
  • L’événement lui-même:
    public event MonHandler On_QuelqueChoseSePassed;
  • Classe « MonEventArgs » :
    public class MonEventArgs : EventArgs
        {
            private int _iInformation1;
            private string _sInformation2;
    
            internal MFluxEventArgs(int iInfo1, string sInfo2)
            {
                _iInformation1 = iInfo1;
                _sInformation2 = sInfo2;
            }
    
            public int Information1
            {
                get { return _iInformation1; }
            }
    
            public string Information2
            {
                get { return _sInformation2; }
            }
        }
  • Fonction qui lance l’événement :
        private void FireQuelqueChoseSePassed(MonEventArgs e)
        {
            if (On_QuelqueChoseSePassed != ')
            {
                On_QuelqueChoseSePassed(this, e);
            }
        }

 

  • Maintenant, dans mon code, je vais avertir quand quelque chose se passe :

    ...
    FireQuelqueChoseSePassed(new MFluxEventArgs(15, "On est ici"));
    ...
  • 2- AILLEURS, on souhaite s’abonner à l’événement :
  • On abonne une fonction de la même signature que le delegate :

    MaClasse.On_QuelqueChoseSePassed +=new MaClasse.MonHandler(LaFonctionQuiVaRecevoirLEvent);
  • La fonction abonnée :

    protected void LaFonctionQuiVaRecevoirLEvent(object sender, MonEventArgs e)
    {

    // Ici, on peut utiliser "sender" (objet MaClasse instancié), ou "e" (qui contient un entier et un string...)

    }