The blog of dlaa.me

An image is worth a thousand HTML tags [How to: Display a custom image with an ASP.NET web page]

Imagine that you want to generate a custom image for your web site and that the content of the image will be dynamic enough that it's not possible to create the images beforehand. (One example might be an image of a clock displaying the current time.) It sure would be nice if you were able to create that image from an ASP.NET .aspx page whenever it was needed. But .aspx pages have to return HTML code, don't they? As it happens, they don't! While that's the job they perform most of the time, they can actually return any arbitrary data you'd like.

In this case, we want figure out how to return an image. Like many things in life, it's pretty easy once you know where to look. Specifically, the MSDN documentation for the HttpResponse.OutputStream property is a great place to start. The example on that page shows how to generate a custom JPEG image and return it from an ASP.NET .aspx page. Click the "Copy Code" link, create a new ASP.NET web site in your favorite editor, replace the contents of Default.aspx with the sample code, and view it in your favorite browser. Problem solved! (Well, close enough - customizing that image is left as an exercise to the reader. :) )

Digging a little deeper, we see that the sample code looks something like this:

private void Page_Load(object sender, EventArgs e)
{
    // Set the page's content type to JPEG files
    // and clear all response headers.
    Response.ContentType = "image/jpeg";
    Response.Clear();

    // Buffer response so that page is sent
    // after processing is complete.
    Response.BufferOutput = true;

    // ...
 
    // Create integer variables.
    int height = 100;
    int width = 200;

    // ...

    // Create a bitmap and use it to create a
    // Graphics object.
    Bitmap bmp = new Bitmap(
        width, height, PixelFormat.Format24bppRgb);
    Graphics g = Graphics.FromImage(bmp);

    // ...

    g.Clear(Color.LightGray);
    
    // ...
    
    // Save the bitmap to the response stream and
    // convert it to JPEG format.
    bmp.Save(Response.OutputStream, ImageFormat.Jpeg);

    // Release memory used by the Graphics object
    // and the bitmap.
    g.Dispose();
    bmp.Dispose();

    // Send the output to the client.
    Response.Flush();
}

Were I to use this code in a web page, I might change it to look a little more like this:

private void Page_Load(object sender, EventArgs e)
{
    // Set the page's content type to JPEG files
    // and clear all response headers.
    Response.ContentType = "image/jpeg";
    Response.Clear();

    // ...
 
    // Create integer variables.
    int height = 100;
    int width = 200;

    // ...

    // Create a bitmap and use it to create a
    // Graphics object.
    using (Bitmap bmp = new Bitmap(
        width, height, PixelFormat.Format24bppRgb))
    {
        using (Graphics g = Graphics.FromImage(bmp))
        {

            // ...

            g.Clear(Color.LightGray);

            // ...

        }

        // Save the bitmap to the response stream and
        // convert it to JPEG format.
        bmp.Save(Response.OutputStream, ImageFormat.Jpeg);
    }
}

Why? Well, I made three basic changes that I believe improve upon the original sample:

  1. I removed the use of HttpResponse.BufferOutput and HttpResponse.Flush. There seems to me to be no need to restrict the flow of data to the client in this case (on the contrary, let's allow it to start rendering the image as soon as possible). Unnecessary code is bad code, so it's gone.
  2. I converted the sample to take advantage of the using statement. You can read more about using in MSDN or wait for my next post in which I'll cover this handy statement in more detail.
  3. I dispose of the Graphics object as soon as it's no longer needed. Again, I'll cover the reasons for this in more detail in my post about the using statement.

So there you have it: Custom image generation with ASP.NET. It's easy to do and it leverages all your existing knowledge about graphics under .NET!

Tags: Technical