Image Transforms with the ASP.NET Generated Image ControlBy Scott Mitchell
Last week's article - Dynamically Generating and Caching Images in ASP.NET with the GeneratedImage Control - looked at how to programmatically create and cache images on the fly using the GeneratedImage control, one of a suite of "Futures" technologies found in the ASP.NET Team's CodePlex site. Programmatically creating and displaying images entails the use of an HTTP Handler for generating the binary content of the dynamically-generated image. While this HTTP Handler can be implemented as an ASP.NET page, the GeneratedImage control includes the
ImageHandlerclass, which serves as a base class for HTTP Handlers designed specifically to generate and serve dynamic images and includes built-in functionality for caching images on the client and/or web server. Last week's article illustrated both how to create an HTTP Handler for generating dynamic images (one that extended
ImageHandler) as well as how to use the GeneratedImage Web control to display such dynamically-generated images in a web page.
In addition to its image generation and caching features, the
ImageHandler class includes functionality for performing image transforms. An image
transformation is a process that takes an image as input, modifies it in some way, and outputs the modified image. Common image transformations include image resizing,
changing the image's color information (such as transforming a color image into a black and white one), and adding a watermark to the image. What's more, transformations can
be chained together. For example, you could take an original image and feed in into the resize transformation. The output of the resize transformation could then be used as
the input of the watermark transformation, which would then output the resized image with a watermark.
The GeneratedImage control ships with an image transform class that resizes the original image, as well as an
ImageTransform class that serves as a base class
for creating your own image transform classes. This article illustrates how to use resize dynamically-created images on the fly as well as how to create your own image transform
classes. Read on to learn more!
Applying Image Transforms
ImageHandlerclass, which serves as a base class for the HTTP Handler classes used to dynamically generate images using the GeneratedImage control, includes a property named
ImageTransformsthat specifies what image transforms (and in what order) are applied to the generated image. Specifically, the
ImageTransformsproperty holds a collection of objects that derive from the
ImageTransformclass is another class in the GeneratedImage API that serves as a base class for classes that can perform image transforms. The API includes a class named
ImageResizeTransform, which extends
ImageTransform. (We'll look at using the
ImageResizeTransformshortly, and later we'll see how you can create your own custom image transform classes).
To apply an image transform to a dynamically-generated image, simply add an instance of the image transform class to the
ImageTransforms property in either the
HTTP Handler's constructor or in the
GenerateImage method. For instance, the following HTTP Handler snippet applies two image transform classes to the image generated
by the HTTP Handler.
As you can see from the code above, you can apply any number of image transform classes to the
If the image transform class does not require that you set any property values, you can instantiate the image transform class directly in the call to the
Add method, as in
MyBase.ImageTransforms.Add(New SomeImageTransformClass). More likely, you'll need
to first set a variety of properties of the image transform class. In that case, start by creating an instance of the image transform class, set its properties, and then add
the instance to the
Keep in mind that the specified image transforms are applied after the image is generated by the
GenerateImage method. Furthermore, the transforms are applied
in the order in which they appear in the
ImageTransforms list. In other words, with the above example the
GenerateImage method is responsible for
creating the original image. Next, the
SomeImageTransformClass image transform class is applied to the original image. It's output is then fed as input into
SomeOtherImageTransformClass image transform class and that output is what is returned to the client.
Resizing Images With The
The GeneratedImage API ships with a built-in image transform class,
ImageResizeTransform. As its name implies,
ImageResizeTransformresizes the original image to an alternate size. This is particularly useful in websites where there are commonly very large, high-resolution pictures that need to sometimes be shown in a smaller, more compact view.
Consider a website like Flickr, which allows visitors to upload their digital pictures. Typically, digital pictures are very large, both in terms
of file size and dimensions. For example, a digital picture might be more than 2,000 pixels wide by 1,000 pixels tall and consume upwards of 1 MB of disk space. Clearly, displaying
such images on your website will not only stretch out your pages, but also greatly impact the total bandwidth used by the site. When you sign on to Flickr you see your
picture library as a series of resized images that do not exceed 240 pixels in width, thereby permitting multiple columns of pictures to be listed on a single page.
While the ASP.NET Image web control has
Height properties that let you specify the dimensions of the image on the browser, these properties
do not actually resize the image. Instead, the web server still transmits the entire contents of the original image, which the browser then scales to the specified width and height.
In order to reduce both the dimensions and the file size, you need to resize the image.
If you have a predetermined, known quantity of high-resolution images, you can proactively create smaller versions of these images using an image editing program like Photoshop.
But if your site has user-added pictures or dynamically-generated images, and you need to resize these source images into smaller versions, then you'll need to resize the image
dynamically. This is where the
ImageResizeTransform class can help.
The following code snippet shows an HTTP Handler that extends the
ImageHandler class and uses the
ImageResizeTransform class to resize an image file
to a width of 200 pixels. (The resized image's height is automatically scaled to the appropriate height.) Specifically, this code resizes an image file that resides on the
web server's file system (note that the URL to the image to resize is specified via the
parameters collection), although the resize transform could be applied
to a dynamically-generated image.
In the HTTP Handler's constructor an instance of the
ImageResizeTransform class is created and its
Width property is set to 200, which resizes
the resulting image to 200 pixels with the height auto-scaled. The
GenerateImage method reads in the
ImageUrl parameter, which contains the
path to the image to resize. This parameter contains the virtual path to the image, such as
~/Images/Picture.jpg. In order to load the image we need to know
the physical path, such as
C:\MyWebsite\Images\Picture.jpg. This translation from virtual to physical paths is performed by the
method and saved in the
imageFile variable. Next, a check is performed to ensure that the file exists; if it does not, an
thrown. However, if the image exists then its bytes are read via the
File.ReadAllBytes method and passed into the constructor for a new
object, which is what the
GenerateImage method must return.
GenerateImage method completes, the
ImageHandler applies the
ImageResizeTransform transform, which resizes the specified
image to have a width of 200 pixels. This resized image is what is returned to the requesting client.
The download available at the end of this article includes a more refined resizing HTTP Handler, one where the width or height of the resized image can also be specified
parameters collection. This HTTP Handler can be found in the demo at
~/ImageHandlers/ResizeImageHandler.ashx; there's also a web page named
~/Demos/TransformDemo.aspx that contains a GeneratedImage Web control with the following declarative markup:
The original image,
Hiking.jpg, an original resolution of 2589 x 1249 and over 940 KB in size and resizing it to 400 x 193 pixels with a total file size of
32 KB. To see this resizing in action, download the demo or check out the
original picture and compare it with the resized one below.
Creating a Custom Image Transform Class
ImageResizeTransformclass derives from the
ImageTransformclass, which spells out the base functionality of a class that performs image transforms. Specifically, the
ImageTransformclass includes an abstract method (one that must be overridden) named
ProcessImage, which is responsible for performing the transform. The
ProcessImagemethod is passed an
Imageobject as input and returns the transformed image as its output (also as an
It is possible to create your own image transform classes and to use them in your HTTP Handlers. The demo available for download at the end of this article includes a custom
image transform class named
ImageWatermarkTransform. As its name implies,
ImageWatermarkTransform transforms the input image by adding a watermark.
This image transform class contains properties like
FontFamily, and other properties that affect the
display and rendering of the watermark. In the
ProcessImage method it takes the input image and adds the watermark, locating it in the center of the image.
The following code snippet shows the germane parts of the
ImageWatermarkTransform class, namely the
ProcessImage method. This method starts by creating
Font object based on the values of the class's
FontSize properties. Next, a
Graphics object is created to work on the
input image (
image). The size of the watermark is measured; next, the coordinates to place the watermark and the center of the image are computed. Finally, the
watermark is added to the image via the
DrawString method, and the modified image is returned.
In addition to creating this image transform class, I also created an HTTP Handler named
WatermarkAndResizeImageHandler.ashx that uses both the
ImageResizeTransform transform classes to first (optionally) resize an image and then to (optionally) add a watermark. The code is quite similar to that of the
ResizeImageHandler.ashx HTTP Handler, which we examined earlier in this article. The only difference is the addition of the
which is highlighted in the snippet below.
WatermarkDemo.aspx page uses the GeneratedImage Web control to display the
Hiking.jpg photo resized to 350 pixels wide (and auto-scaled to
168 pixels tall) with the watermark "Copyright Scott Mitchell" prominently displayed using a yellow, Comic Sans MS font of size 18pt.
Keep in mind that the image transforms are applied in the order they appear in the
ImageTransforms list. In the above example, the image is first resized
and then a watermark is added. However, if you reversed the order with which the image transform classes are added to the
ImageTransforms property then the image
would first have a watermark added and then be resized.
The ASP.NET GeneratedImage control makes it easy to work with dynamically-generated images. This article (and last week's article) showed how to use this control and the classes that make up its API to serve dynamic images, cache them, and apply image transforms. The GeneratedImage control ships with one built-in image transform class,
ImageResizeTransform. You can also create your own custom image transform classes, as this article illustrated.