GDI+, is a .Net model for rendering dynamic graphics. In this article, we are going to discuss how to render custom graphics with GDI+ and embedding these graphics in a web page. Lastly we will look into charting with GD+ and create a simple pie chart.

Introduction:

GDI+, is a .Net model for rendering dynamic graphics. In this article, we are going to discuss how to render custom graphics with GDI+ and embedding these graphics in a web page. Lastly we will look into charting with GD+ and create a simple pie chart.

Drawing with GDI+:

The heart of the GDI+ programming is the System.Drawing.Graphic class. With GDI+ programming model you can create rich graphics using user-specific information or you can even render charts and graphs on the fly based on the records in a database. To create graphics using GDI+ in ASP.Net, you need to go through the following steps:

• Creating the in-memory bitmap where you perform the drawing.
• Creating a GDI+ graphics context for the image. This involves creating an object of the Graphics class.
• Drawing images using the methods of the Graphics object. You can draw and fill lines and shapes and can copy content from files.
• Writing the binary data for the image to the browser, using the Response.OutputStream property.

To use GDI+, you must import the following namespaces:

using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;


Let us create a very simple drawing to understand the above mentioned steps. All the code is written in the event handler of the Page_Load event:

The first step is to create the in-memory bitmap. For this we create an instance of the System.Drawing.Bitmap class. We need to specify the height and width of the image in pixels as the parameters to the constructor. It is better to keep the bitmap size as small as possible as a larger bitmap will consume additional server memory and slow down transmission.

Bitmap image = new Bitmap(400, 150);

In the next step we create a GDI+ graphics context for the image, which involves creating the Graphics object. The methods of this object allows to draw content on the in-memory bitmap.

Graphics g = Graphics.FromImage(image);

Next we perform some creative activity by using the commonly used methods of the Graphics class. The FillRectangle( ) method draws the rectangle shape in the memory. The DrawString method draws a string inside the image. The code is simple and self explanatory.

g.FillRectangle(Brushes.AntiqueWhite, 1, 1, 398, 148);
Font font = new Font("Impact", 26, FontStyle.Bold);
g.DrawString(" Welcome to GDI+ World.", font, Brushes.Brown, 10, 5);


Last step is to send the image to the browser using the Image.Save() method. The image is saved to the response stream of the browser. You need to release the image and graphics context when you’re finished. The Dispose() method is used to release these resources.

image.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Gif);
g.Dispose();
image.Dispose();


Output of the above code:

 


The Graphics Class:

The Graphics class provides most of the method for drawing shapes, images and text. So, let us have a look into the methods of the class before trying to create a more complex drawing.

Methods of Graphics Class:

DrawArc(): It draws an arc representing a portion of an ellipse specified by a pair of coordinates, a width and a height.
DrawBezier() and DrawBeziers():    Draws the Bezier curve, defined by four control points
DrawClosedCurve(): Draws a curve and closes it connecting the endpoints
DrawCurve(): Draws a curve
DrawEllipse(): Draws an ellipse defined by the bounding rectangle specified by pair of coordinates, height and width
DrawIcon() and DrawIconUnstreched(): Draws an icon represented by an Icon object and stretches it to fit a given rectangle
DrawImage() and DrawImageUnscaled(): Draws an image and stretches it to fit a given rectangle
DrawLine() and DrawLines(): Draws a line connecting two points
DrawPath(): Draws a GraphicsPath object. This is an important object which represent a combination of curves and shapes
DrawPie(): Draws a piece-of-pie shape, defined by an ellipse specified by a coordinate pair, a width, a height, and two radial lines
DrawPolygon(): Draws a multisided polygon defined by an array of points
DrawRectangle() and DrawRectangles(): Draws rectangles specified by staring coordinate pair and width and height
DrawString(): Draws a string of text in a given font
FillClosedCurve(): Draws a closed curve and fills it
FillEllipse(): Fills the interior of an ellipse
FillPath(): Fills the shape represented by a GraphicsPath object
FillPie(): Fills the interior of a pie-shape
FillPolygon(): Fills the interior of a polygon
FillRectangle() and FillRectangles(): Fills the interior of a rectangle
FillRegion(): Fills the interior of a Region object

Pens and Brushes:

The System.Drawing.Pens class provides pens of 1 pixel width and of variety of colors. This class is used with any of the DrawXxx() methods of the Graphics class. You can create a pen object by creating an instance of the Pen class:

Pen mypen = Pens.Black;

The properties of this class are:
• DashPattern
• DashStyle
• LineJoin
• PenType
• StartCap and EndCap
• Width

Brushes are used to fill the space between lines, when you use any of the FillXxx() methods of Graphics class for filling the interior of any shape.

Brush mybrush = Brushes.Brown;

The brush created above is a solid brush, other brush options are:

• HatchBrush :
• LinearGradientBrush
• TextureBrush

Creating a Simple Pie-Chart:

This example uses GDI+ to create a graphical pie chart. User adds each slice of pie in angle using a web page, and the image is drawn. In a more realistic case, it should be built on the basis of information in a database and slice of pie should be determined on percent basis.
The System collection is used to store the slices added by the user, each time and the page is rendered on the basis of the session data.

The PieSlice class defines the pie slice:

public class PieSlice
{
    private float dataValue;
    private string caption;

    public float DataValue
    {
        get { return dataValue; }
        set { dataValue = value; }
    }

    public string Caption
    {
        get { return caption; }
        set { caption = value; }
    }

    public PieSlice(string caption, float dataValue)
    {
        Caption = caption;
        DataValue = dataValue;
    }

    public override string ToString()
    {
        return Caption + " (" + DataValue.ToString() + ")";
    }

}


There are two .aspx files involves in this project. The CreateChart.aspx file allows the user to create the pie chart. When user enters a label and an angle value; and clicks on the ‘Add...’ button, the PieSlice object is created and stored in a list box. Every time the page is processed and the Page.PreRender event fires, all the PieSlice objects in the list box are stored in the session state. Every time the page loads i.e., the Page.Load event is fired the PieSlice objects are retrieved from session state. The code is shown here:

public partial class CreateChart : System.Web.UI.Page
{

    private ArrayList pieSlices = new ArrayList();

    protected void Page_Load(object sender, System.EventArgs e)
    {
        // Retrieve the pie slices that are defined so far.
        if (Session["ChartData"] != null)
        {
            pieSlices = (ArrayList)Session["ChartData"];
        }
    }

    protected void cmdAdd_Click(object sender, System.EventArgs e)
    {
        PieSlice pieSlice = new PieSlice(txtLabel.Text, Single.Parse(txtValue.Text));
        pieSlices.Add(pieSlice);

        // Bind the list box to the new data.
        lstPieSlices.DataSource = pieSlices;
        lstPieSlices.DataBind();
    }

    protected void CreateChart_PreRender(object sender, System.EventArgs e)
    {
        // Before rendering the page, store the current collection
        // of pie slices.
        Session["ChartData"] = pieSlices;
    }
}



The DynamicChart.aspx creates the bitmap, retrieves the objects and draws the pie slices and legend. The Page.Load event of this class is presented here:

protected void Page_Load(object sender, System.EventArgs e)
    {
        // Create the in-memory bitmap where you will draw the image.
        Bitmap image = new Bitmap(300, 200);
        Graphics g = Graphics.FromImage(image);

        g.FillRectangle(Brushes.White, 0, 0, 300, 200);
        g.SmoothingMode = SmoothingMode.AntiAlias;

        if (Session["ChartData"] != null)
        {
            // Retrieve the chart data.
            ArrayList chartData = (ArrayList)Session["ChartData"];

            // Write some text to the image.
            g.DrawString("Sample Chart", new Font("Georgia", 18, FontStyle.Bold), Brushes.Black, new PointF(5, 5));

            // Calculate the total of all data values.
            float total = 0;
            foreach (PieSlice item in chartData)
            {
                total += item.DataValue;
            }

            // Draw the pie slices.
            float currentAngle = 0, totalAngle = 0;
            int i = 0;
            foreach (PieSlice item in chartData)
            {
                currentAngle = item.DataValue / total * 360;
                g.FillPie(new SolidBrush(GetColor(i)), 10, 40, 150, 150, (float)Math.Round(totalAngle), (float)Math.Round(currentAngle));
                totalAngle += currentAngle;
                i++;
            }

            // Create a legend for the chart.
            PointF colorBoxPoint = new PointF(200, 83);
            PointF textPoint = new PointF(222, 80);

            i = 0;
            foreach (PieSlice item in chartData)
            {
                g.FillRectangle(new SolidBrush(GetColor(i)), colorBoxPoint.X, colorBoxPoint.Y, 20, 10);
                g.DrawString(item.Caption, new Font("Tahoma", 10), Brushes.Black, textPoint);
                colorBoxPoint.Y += 15;
                textPoint.Y += 15;
                i++;
            }

            // Render the image to the HTML output stream.
            image.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Gif);
        }
    }

You can download the entire project here. The output of the code:


 

Conclusion:

The .Net Framework 3.0/3.5 provides a brand new API called Windows Presentation Foundation, which takes care of graphics in your page in a more composed way. But you can still use GDI+ to add more power to your sites.

[Download]