Dynamically Generating and Caching Images in ASP.NET with the GeneratedImage Control
By Scott Mitchell
Introduction
CodePlex is Microsoft's open source project community and provides a free hosting platform for open source projects created in .NET. Microsoft's own ASP.NET team has its own CodePlex page - aspnet.CodePlex.com - where they give code previews for upcoming releases. There you'll find the ASP.NET MVC 1.0 source code, a preview of the ASP.NET AJAX 4.0 Framework, and other future libraries, frameworks, and controls.
One of the controls on the ASP.NET team's CodePlex page that gets little press is the GeneratedImage control. The GeneratedImage control is a combination of an ASP.NET Web Control and a set of classes that facilitate programmatically creating, serving, caching, and transforming images. If you store images in the database that need to be served from a web page, if you need to create images on the fly, or if you need to resize, add watermarks, or perform some other image transform, then the GeneratedImage control can help.
This article looks at using the GeneratedImage control. Specifically, we'll see how to generate dynamic images on the fly based on a variety of inputs. We'll also look at how to cache images. Read on to learn more!
The Impetus for Programmatically Serving Images
In most websites, images are static files and are displayed on a web page through the
<img>
HTML element or the ASP.NET Image Web control (which renders
an <img>
element). However, there are times when images need to be served dynamically. Consider a dating website where members can upload pictures of
themselves. These pictures need to be stored somewhere, either on the web server's file system or directly in the database. If the images are stored on the file system then
they can be displayed by an <img>
HTML element or the ASP.NET Image Web control, but if the images are stored within the database then special steps
must be taken to extract the image from the database and send it down to the client. This typically entails creating an ASP.NET page whose sole purpose is to serve
images from the database. (See Storing Binary Files Directly in the Database Using ASP.NET 2.0 for
how to use an ASP.NET page to serve content stored in a database.)
Other cases when being able to serve images dynamically include scenarios where the image needs to be generated on the fly or when an image - either static or dynamic - needs
to be modified in some way before being served. Consider an image gallery website where users can upload pictures taken from a digital camera. Chances are these uploaded
images are going to be quite large in both their dimensions and file size. When displaying a users images through a web page you might want to resize the image to a maximum
width or height so that the image fits within the page's design. While you can constrain an image's dimensions via the ASP.NET Image control's Width
and
Height
properties, doing so only affects how the browser sizes the image. The full image is still sent down to the client. However, resizing the image on the
server and then sending this resized image to the browser can greatly reduce your site's total bandwidth and provide a snappier user experience.
In order to programmatically serve an image you need to create an HTTP Handler on the server whose sole responsibility is to perform whatever image manipulations are needed - constructing the image, resizing it, caching it on disk, and so forth - and then returns it to the client. An HTTP Handler is an object in an ASP.NET application that serves content. All ASP.NET pages are themselves HTTP Handlers, so it is possible to create an ASP.NET page whose responsibility is to process and serve an image. However, it's also possible (and a bit more efficient) to create a slimmer, more focused HTTP Handler. (For more information on how HTTP Handlers work and how to create your own HTTP Handlers, refer to How ASP.NET Web Pages are Processed on the Web Server and Serving Dynamic Content with HTTP Handlers.)
Once the HTTP Handler (or ASP.NET page) has been created, the images can be served from an <img>
HTML element or ASP.NET Image Web control by having the
image reference the HTTP Handler (or ASP.NET page). For instance, imagine that you have a database table that stores information about employees and contains a varbinary
column in the Employees
table that stores the binary contents of a picture of each employee. To view this picture from a web page on the intranet you would first
create a page (or HTTP Handler) that serves the picture, namely a page that connects to the database, pulls down the binary contents of the picture for a particular employee,
and then returns that binary content to the requesting client. Image that this page was named ShowEmployeePicture.aspx
and that it was passed an EmployeeID
value through
its querystring to determine which employee's picture to display. In other words, visiting ShowEmployeePicture.aspx?EmployeeID=1
would display the picture for the employee
whose EmployeeID
is 1.
To display a particular employee's picture in a web page you might use an ASP.NET Image Web control and set its ImageUrl
property to
ShowEmployeePicture.aspx?EmployeeID=ID
. This would send down HTML like <img src="ShowEmployeePicture.aspx?EmployeeID=ID" />
to
the browser, which would cause the browser to make a request to ShowEmployeePicture.aspx?EmployeeID=ID
. ShowEmployeePicture.aspx?EmployeeID=ID
would then go get the binary contents of the picture for employee ID and return that to the browser, which would then display the picture.
Introducing the GeneratedImage Control
The GeneratedImage control is a free, open source project from Microsoft's ASP.NET team that facilities creating an HTTP Handler for programmatically generating, caching, and transforming images at runtime on the server. Moreover, this project includes a Web control for displaying dynamic images via an HTTP Handler. The GeneratedImage control was released in August 2008 and works with ASP.NET version 3.5 SP1 and beyond. One thing to keep in mind is that these projects that the ASP.NET team releases on CodePlex are not guaranteed to appear in future releases. The team uses their CodePlex project as sort of a laboratory where they can try out new projects, get feedback, and see how it's used in the wild. Scott Hanselman describes these CodePlex projects thusly:
"There's a treasure trove of interesting stuff over at http://www.codeplex.com/aspnet. It's a bunch of potential future stuff that the ASP.NET team is working on. That's where you can get builds of ASP.NET MVC, Dynamic Data Futures, new AJAX stuff, [and the GeneratedImage control]. ... It's a potential new feature, so it could go nowhere, or we could make T-shirts and sing its praises. Could go either way. No promises.So keep in mind that this control is not officially part of the ASP.NET stack, nor is it officially supported by Microsoft or guaranteed to be in any future releases. Moreover, there are some loose ends with the GeneratedImage control. For instance, the GeneratedImage control library includes a mechanism to implement caching dynamically-generated images on the web server. Right now there's only one implementation, to cache the image on the web server's file system. This implementation has some hard-coded decisions that should really be configurable, such as the duration for which the image is cached on the file system. Furthermore, the infrastructure's present to allow for other caching stores, such as caching the dynamically-generated images in memory, yet there is no memory cache option. Perhaps these loose ends will be tied up and the GeneratedImage control will be released as part of ASP.NET 4.0 (or beyond).
Downloading the GeneratedImage Control and Adding It To Your Website
The first step to getting started with the GeneratedImage control is to download the control, which you can do from its Releases page in the CodePlex project: http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=16449. At minimum you need to download the
Microsoft.Web.GeneratedImage.dll
assembly; you can also download a project road map and a variety of samples of the GeneratedImage control
in action.
To use the GeneratedImage control in an ASP.NET application you need to add this assembly to your project's Bin
folder. If you use Visual Studio's Web Site Project
model then you can simply add the assembly to the Bin
folder. If you use the Web Application Project model then you should right-click on the project in
the Solution Explorer, choose Add References, and browse to the assembly.
The GeneratedImage control assembly (Microsoft.Web.GeneratedImage.dll
) also includes a Web control (GeneratedImage), which you can optionally add to the Toolbox in
Visual Studio. To do so, right-click within the Visual Studio Toolbox, select Choose Items, and then Browse to the Microsoft.Web.GeneratedImage.dll
file on your
hard drive. This adds a new control to the Toolbox, GeneratedImage, as the screen shot to the right shows.
Creating a Simple GeneratedImage HTTP Handler
As we discussed earlier, in order to programmatically serve an image we need to create an ASP.NET page or HTTP Handler that's responsible for generating the image. The The GeneratedImage control library includes an HTTP Handler base class named
ImageHandler
that provides the base functionality for an image serving HTTP Handler.
Therefore, we can create an HTTP Handler that derives from this base class and contains the code that generates the image of interest.
Start by adding a new HTTP Handler to your website by choosing to add a new Generic Handler item. (Right-click on the project name or a folder in the Solution Explorer, choose
Add New Item, and then select the Generic Handler option from the Add New Item dialog box.) HTTP Handlers generally have the extension .ashx
, so name this handler
something like MyImageHandler.ashx
. Keep in mind that this HTTP Handler is responsible for serving image content and will be cited in <img>
elements
and ASP.NET Image Web controls. Therefore, make sure that you do not place this file in the App_Code
folder, the App_Data
folder, or in any other
non-accessible location.
HTTP Handlers must implement the IHttpHandler
interface; when adding a new HTTP Handler Visual Studio creates a class that implements this interface. However, we want our
HTTP Handler to inherit from ImageHandler (which implements IHttpHandler
), therefore gut the boilerplate class definition Visual Studio added and replace it with
the following:
<%@ WebHandler Language="VB" Class="MyFirstImageHandler" %>
|
There are three things to note in the above code sample. First, note that I've imported the System.Drawing
and Microsoft.Web
namespaces. The
System.Drawing
namespace contains the GDI+ classes for working with images programmatically; the Microsoft.Web
namespace contains the GeneratedImage
control API, and includes the ImageHandler
base class. Next, note that the HTTP Handler class inherits from the ImageHandler
class.
Finally, note that the body of the HTTP Handler class contains two methods:
- The Constructor (
Public Sub New()
) - you can put any initialization logic here, such as the image type generated by the HTTP Handler (JPG, PNG, GIF, etc.) - The
GenerateImage
Method - this method is the workhorse of the HTTP Handler. It is passed a collection of parameter values and must return anImageInfo
object. TheImageInfo
object contains the image content to send down to the client.
TextToImageHandler.ashx
and uses the GDI+ classes to generate an image from text. As the code below shows, the text that is turned into an image,
along with the font settings, colors, and so forth - are hard-coded in the HTTP Handler. In a nutshell, the HTTP Handler below generates an image that displays the text
"Hello, World!" in black on a yellow background using the Verdana font, 14pt size and with 5 pixels of horizontal and vertical padding on the top, bottom, left, and right of
the text.
<%@ WebHandler Language="VB" Class="TextToImageHandler" %>
|
generated as a PNG. The GenerateImage
method defines the hard-coded values and then calls the CreateImage
method and passes it these hard-coded values.
The CreateImage
method starts by creating a dummy Bitmap
and Graphics
object in order to determine how much vertical and horizontal space
the text to be displayed will occupy. Once this is known, new Bitmap
and Graphics
objects are created to render the image. First, a Bitmap
object with the appropriate dimensions is created. Next, a Graphics
object is created from the Bitmap
and its Clear
method is used to
blanket the background with the specified color. The DrawString
method adds the specified textual message to the image and a new ImageInfo
object is created
based on the Bitmap
object and returned.
Whenever this HTTP Handler is visited - such as through
http://www.yoursite.com/TextToImageHandler.ashx
- the page returns a PNG image to the browser with the
text "Hello, World!", which is shown to the right. As far as the browser is concerned, this URL is just like any other PNG or JPG or GIF file it would normally request from
a web server. You could display this image using an ASP.NET Image Web control and settings its ImageUrl
property to TextToImageHandler.ashx
.
Another way to display the image dynamically generated by the TextToImageHandler.ashx
HTTP Handler is to use the GeneratedImage control, which is a custom compiled
Web control. Assuming you added this control to the Toolbox, drag it onto an ASP.NET page and set its ImageHandlerUrl
property to the URL of the HTTP Handler.
The GeneratedImage control renders into an <img>
element referencing the HTTP Handler in the <img>
element's src
attribute.
The following is a screen shot from the ~/Demos/SimpleTextToImageDemo.aspx
page, which uses the GeneratedImage control to display the "Hello, World!" image.

Generating An Image Based On Parameters
The image generated by the
TextToImageHandler.ashx
HTTP Handler is pretty pointless because it's text, font, and size are all static. If you want to display a
static image, why not just create an image file? Using an HTTP Handler is overkill. However, HTTP Handlers are useful for dynamic images, ones whose content is based on
external parameters.
Recall that the GenerateImage
method is passed a set of parameters. The parameter names and values passed into this list are the collection of querystring
parameters included in the call to the HTTP Handler. In other words, if an <img>
element requests the HTTP Handler like so:
<img src="TextToImageHandler.ashx?Message=Powered+By+ASP.NET" />
|
Then when the GenerateImage
method is invoked it will have a single parameter in its parameters collection named Message
and with the value
"Powered By ASP.NET". We can augment the TextToImageHandler.ashx
HTTP Handler to base its message, colors, font, and other information on parameters,
and doing so only involves fleshing out the GenerateImage
method in the example above to read in the values from the parameters collection rather than using
hard-coded values. The download at the end of this article includes an HTTP Handler named TextToImageHandler2.ashx
that includes this flexibility. The
updated GenerateImage
method is shown below.
Public Class TextToImageHandler2
|
With this updated HTTP Handler you can create dynamic images with any text, colors, fonts, and padding. As aforementioned, the parameters passed into the GenerateImage
method are those that come in through the querystring, but you can supply these parameters programmatically or declaratively via the GeneratedImage Web control, which has
a Parameters
collection. The ~/Demos/TextToImageDemo.aspx
page in the download has a GeneratedImage Web control that has five parameters
specified through its declarative markup: Message
, Font
, FontSize
, FontColor
, and BackColor
.
<cc1:GeneratedImage ID="TextAsImageGenerator" runat="server" ImageHandlerUrl="~/ImageHandlers/TextToImageHandler2.ashx">
|
The result is the following image.

These parameters can also be set programmatically. The ~/Demos/TextToImageDemo.aspx
page also contains a Web Form where a user can enter their own textual message
and choose various font and style properties. On clicking "Update Image," the GeneratedImage control's Parameters
collection is updated to reflect the user's
input, which generates a matching image.

Caching Dynamically Generated Images
By default, each time an image HTTP Handler is requested it executes its
GenerateImage
method, generates the image, and sends the image contents to the requesting
client. This may result in a lot of unnecessary work if the image being generated changes infrequently or does not change for a given set of input parameters. For such scenarios,
you may want to cache the image.
The ImageHandler
class from which our HTTP Handler inherits, can implement client-side and server-side caching via its EnableClientCache
and
EnableServerCache
properties. Both these properties default to False. To enable caching you need to set them to True, which you can do in the constructor.
Enabling client caching instructs the ImageHandler
class to set the Response.Cache
object's cache-ability to Public and to set the expiry to
the TimeSpan
value specified by the ImageHandler
's ClientCacheExpiration
property. In a nutshell, setting EnableClientCache
causes the image request to include an HTTP header that tells the browser that it can cache the image for a time specified by the ClientCacheExpiration
property
(say, ten minutes). That means that if the browser visits a page on the site that references the same image within the next ten minutes, the browser will serve the image from
its local cache rather than making a request to the web server for the image.
If you set the EnableServerCache
property to True then the ImageHandler
class saves a copy of the generated image to the web server's file system.
Specifically, these files are saved in the App_Data/_imagecache
folder, which is automatically created if it does not already exist. If a request comes in for
an image that is cached on disk, the cached copy is sent back to the browser instead of having the image re-generated via the GenerateImage
method.
The disk-based cache has a hard-coded expiry of five minutes, meaning that after five minutes, the cached image files are deleted.
Keep in mind that the cached image files are specific to the input parameters (if any) passed into the HTTP Handler. For example, if you are using server-side caching and a
user makes a request to the TextToImageHandler2.ashx
HTTP Handler passing in a Message
value of "Hello, World!", the generated image is cached to
disk on the server. If another request comes in for that same image within the next five minutes, the cached version is returned. However, if a request comes in to
TextToImageHandler2.ashx
with a Message
value of "To be or not to be", a separate cache instance is created. The same concept applies to client-side
caching because the parameters are passed through the querystring and the browser caches based on the full URL, including the querystring.
Conclusion
The GeneratedImage control simplifies serving dynamic images from an ASP.NET website. The project includes both a custom, compiled Web control (GeneratedImage) along with a number of classes that assist in creating an image-serving HTTP Handler. In this article we saw how to create an HTTP Handler to serve images that extends the
ImageHandler
class, as well as how to use the GeneratedImage Web control to display images generated by these HTTP Handlers.
One feature of this project that we have not yet explored is its ability to transform images. With a single line of code you can apply an image transform class to the dynamically-generated image. The project ships with a single image transform class that resizes an image, but you can create your own image transform classes to add watermarks, rotate images, and perform other common transforms. This functionality is explored in a follow-up article, Image Transforms with the ASP.NET Generated Image Control.
Happy Programming!
Attachments:
Further Reading: