Dynamically Generating and Caching Images in ASP.NET with the GeneratedImage ControlBy Scott Mitchell
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
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
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
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
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.dllassembly; 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
ImageHandlerthat 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
MyImageHandler.ashx. Keep in mind that this HTTP Handler is responsible for serving image content and will be cited in
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
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
There are three things to note in the above code sample. First, note that I've imported the
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
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.)
GenerateImageMethod - this method is the workhorse of the HTTP Handler. It is passed a collection of parameter values and must return an
ImageInfoobject contains the image content to send down to the client.
TextToImageHandler.ashxand 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.
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.
CreateImage method starts by creating a dummy
Graphics object in order to determine how much vertical and horizontal space
the text to be displayed will occupy. Once this is known, new
Graphics objects are created to render the image. First, a
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
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
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.ashxHTTP 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:
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
GenerateImage method is shown below.
With this updated HTTP Handler you can create dynamic images with any text, colors, fonts, and padding. As aforementioned, the parameters passed into the
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
Parameters collection. The
~/Demos/TextToImageDemo.aspx page in the download has a GeneratedImage Web control that has five parameters
specified through its declarative markup:
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
GenerateImagemethod, 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.
ImageHandler class from which our HTTP Handler inherits, can implement client-side and server-side caching via its
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
TimeSpan value specified by the
ClientCacheExpiration property. In a nutshell, setting
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
(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
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.
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
ImageHandlerclass, 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.