GDIplus and C-Sharp Rating Image

How to create a runtime image, overlaying multiple objects and exploiting what the GDI+ classes of the .Net Framework can offer.

With this article I'll try to show how to use .Net GDI+ APIs to combine at runtime physical and virtual images.
There's abundance of help requests, in various forums, about how-to overlay multiple images exploiting .Net tools, I think that the following example could be helpful and clarifying.
As usual let's define a real world scenario to contextualize the theoretical stuff:

  • goal
    create an image to visualize, using the "classical" five stars, a variable rating between 0 and 5 (double type values)
  • instruments
    C#, GDI+ and Adobe® Photoshop, or similar (used to create base images)

The idea is to assemble a sandwich triple-layered image.

  1. On the lowest level we put a background image which will act as a placeholder for the "switched-off" stars. The following image is exactly the one used in this blog:
    PNG file
  2. on the intermediate level we will draw a golden rectangle of variable width, depending on the rating value;
  3. on the top level we set a masked and beveled - for aesthetical purposals - image:
    PNG file

Let's dive into the C# code:

// retrieving and normalizing rating value
float rating = Convert.ToSingle(Request.QueryString["Rating"], System.Globalization.CultureInfo.InvariantCulture)/5F;
// creating an instance of Pacem.Drawing.Image using the background image (see step 1)
// (I will illustrate the OverlayImage method next)
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);
// creating a golden rectangle having the width as fraction related to the rating value 
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(); 

Pacem.Drawing.Image is a class I developed myself to manipulate images. It contains scaling, canvas resizing and - above all - color manipulation methods Photoshop-style with algorithms that render results extremely close to those of the Adobe® software. If you know something better please let me know.

Now we go in depth into a form of the - overloaded - method OverlayImage showing how it works. Here's the code:

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);
    // key instruction for 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();
}
 

That's it.

Take care. Bye.


Feedbacks

no feedbacks yet.

SL2