GDIplus e C-Sharp rating

Come creare un'immagine dalla sovrapposizione di più oggetti, utilizzando gli strumenti forniti dalle API GDI+ del .Net Framework.

Con questo articolo cerco di mostrare come utilizzare le API GDI+ del .Net Framework per combinare tra loro immagini esistenti e virtuali, il tutto a runtime.
Si leggono di molte richieste d'aiuto nei vari forums su come sovrapporre più immagini utilizzando gli strumenti forniti da .Net, penso che l'esempio che sto per trattare sia parecchio utile ed esplicativo.
Al solito definiamo uno scenario verosimile per contestualizzare la teoria astratta:

  • finalità
    creare un'immagine per la visualizzazione, tramite le "classiche" stelle, di un rating variabile da 0 a 5 (valori di tipo double, vale a dire non arrotondati agli interi prossimi)
  • mezzi
    C#, GDI+ e Adobe® Photoshop, o analogo (per la creazione delle immagini base)

L'idea è quella di assemblare un'immagine a mo' di sandwich, strutturata su vari livelli disposti lungo l'asse z (del monitor).

  1. Sul livello più basso predisponiamo un immagine di sfondo che agirà anche da segnaposto per le stellette "spente". L'immagine che vado a riportare è esattamente quella utilizzata in questo blog:
    PNG file
  2. sul livello intermedio andiamo a disegnare un rettangolo giallo-oro di larghezza variabile, in funzione del valore numerico del rating;
  3. sul livello prossimo agli occhi dell'utente disponiamo un'immagine, forata ed arricchita di effetti di smusso, di base bianca (colore dello sfondo della pagina):
    PNG file

Vediamo ora il codice C# utilizzato:

// recupero e normalizzo il valore del rating
float rating = Convert.ToSingle(Request.QueryString["Rating"], System.Globalization.CultureInfo.InvariantCulture)/5F;
// istanzio la classe Pacem.Drawing.Image a partire dall'immaginre di sfondo (punto 1)
// (illustrerò in seguito il metodo OverlayImage che andremo ad utilizzare)
Pacem.Drawing.Image pacemimg = new Pacem.Drawing.Image(Server.MapPath("~/Images/CMerighi/Rating_Lower.png"));
Bitmap rect = new Bitmap(pacemimg.Width, pacemimg.Height);
Graphics graph = Graphics.FromImage(rect);
// creo un rettangolo color oro avente come larghezza la frazione riconducibile al rating  
graph.FillRectangle(Brushes.Gold, new RectangleF(0F, 0F, ((float)pacemimg.Width)*rating, (float)pacemimg.Height));

pacemimg.OverlayImage(rect, Pacem.Drawing.VerticalAnchor.Top, Pacem.Drawing.HorizontalAnchor.Left);
pacemimg.OverlayImage(Server.MapPath("~/Images/CMerighi/Rating_Upper.png"), Pacem.Drawing.VerticalAnchor.Top, Pacem.Drawing.HorizontalAnchor.Left);
rect.Dispose(); graph.Dispose();
Response.ContentType = "image/png";
pacemimg.Flush(Response.OutputStream, "image/png");              
pacemimg.Dispose(); 

La classe Pacem.Drawing.Image è una classe da me sviluppata per la manipolazione delle immagini. Contiene metodi per lo scaling, il ridimensionamento dell'area visualizzabile e soprattutto della manipolazione del colore stile Photoshop con algoritmi che danno risultati pressoché identici a quelli del software della Adobe®. Se ci sono tool che rendono meglio la colorazione fatemeli conoscere.

Vediamo di analizzare una forma del metodo OverlayImage (overloaded), mostrando come agisce. Eccone il codice per esteso:

public void OverlayImage(  
System.Drawing.Image bmp, 
VerticalAnchor vAnchor, 
HorizontalAnchor hAnchor
)
{
    Graphics graph = Graphics.FromImage(bmp);

    int x, y;
    double W, w, H, h;
    // _Bitmap is the inner Bitmap base instance of the Pacem.Drawing.Image class
    W = (double)_Bitmap.Width; H = (double)_Bitmap.Height;
    w = (double)bmp.Width; h = (double)bmp.Height;
    switch (vAnchor)
    {
        case VerticalAnchor.Middle:
            y = (int)((H - h) / 2);
            break;
        case VerticalAnchor.Bottom:
            y = _Bitmap.Height - bmp.Height;
            break;
        default:
            y = 0;
    }
    switch (hAnchor)
    {
        case HorizontalAnchor.Center:
            x = (int)((W - w) / 2);
            break;
        case HorizontalAnchor.Right:
            x = _Bitmap.Width - bmp.Width;
            break;
        default:
            x = 0;
    }
    Rectangle destR = new Rectangle(x, y, bmp.Width, bmp.Height);

    Bitmap _Bmp = new Bitmap(_Bitmap.Width, _Bitmap.Height);
    Graphics _Graph = Graphics.FromImage(_Bmp);
    _Graph.DrawImage(_Bitmap, 0, 0, _Bitmap.Width, _Bitmap.Height);
    // istruzione chiave per l'overlaying
    _Graph.DrawImage(bmp, destR, new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);
    _Bitmap = _Bmp;
    // _Graphics is the inner Graphics base instance of the Pacem.Drawing.Image class
    _Graphics = Graphics.FromImage(_Bitmap);
    bmp.Dispose(); graph.Dispose(); _Graph.Dispose();
}
 

Penso sia tutto.

Take care. Bye.


Feedbacks

no feedbacks yet.

SL2