ASP.NET Futures - Generating Dynamic Images with HttpHandlers gets Easier
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, and new AJAX stuff.
Two days ago a new CodePlex release snuck up on the site. 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.
Justin Beck, an ASP.NET intern, prototyped and design it, then Marcin Dobosz, an ASP.NET Developer tidied it up nicely. Right now it's called ASP.NET Generated Image and you can get a release today.
Why should you care?
I've done a lot of HttpHandlers that generate images. It's usually pretty tedious. When I was working banking, I wrote an example HttpHandler that would take two Check Images (back and front) and composite them into a single image on the server side, then serving up the composite. Usually you're messing around in with MemoryStreams and Images, and then you serialize the result out to the Response.OutputStream, making sure the MIME Types are set appropriately. If you're really clever, you'll remember to do some client-side and appropriate caching, but I rarely see that in the wild.
So what have Justin and Marcin done here?
First, they've created a control with a little design mode "chrome" that makes getting started easier. The control is actually an extension of <asp:image/> that creates an HttpHandler and wires up the the src= attribute to the handler. If that were all, it'd be cute. However, second, and most importantly, they've created a base class that can do caching, transformations and parameter passing for you. It's really nicely factored, IMHO.
Here's a simple example. Put one of these GeneratedImage Controls on the page, and click on it...
Next, click "Create Image Handler." You'll get this in the markup, and a new file in the Project:
public class ImageHandler1 : ImageHandler {
public ImageHandler1() {
// Set caching settings and add image transformations here
// EnableServerCache = true;
}
public override ImageInfo GenerateImage(NameValueCollection parameters) {
// Add image generation logic here and return an instance of ImageInfo
throw new NotImplementedException();
}
}
All I need to do now is override GenerateImage. Any parameters to the control will be in the NameValueCollection. I just need to return a new ImageInfo, and the constructor for ImageInfo can take either an Image, a byte[] or an HttpStatusCode. Clever.
Here, I'll add some text:
<cc1:GeneratedImage ID="GeneratedImage1"
runat="server" ImageHandlerUrl="~/TextImageHandler.ashx" >
<Parameters>
<cc1:ImageParameter Name="Hello" Value="text in an image" />
</Parameters>
</cc1:GeneratedImage>
As I said, that parameter is passed in, and it come from <% %> code or DataBinding or whatever. It doesn't care. Now, I'll draw on an image:
public class TextImageHandler : ImageHandler {
public TextImageHandler() {
this.ContentType = System.Drawing.Imaging.ImageFormat.Png;
}
public override ImageInfo GenerateImage(NameValueCollection parameters) {
// Add image generation logic here and return an instance of ImageInfo
Bitmap bit = new Bitmap(300, 60);
Graphics gra = Graphics.FromImage(bit);
gra.Clear(Color.AliceBlue);
gra.DrawString(parameters["Hello"], new Font(FontFamily.GenericSansSerif, 16), Brushes.Black, 0, 0);
return new ImageInfo(bit);
}
}
Which results in...
Slick. What else can I do easily? Let's right-click on the ImageHandler base class and see what it looks like:
namespace Microsoft.Web
{
public abstract class ImageHandler : IHttpHandler
{
protected ImageHandler();
public TimeSpan ClientCacheExpiration { get; set; }
public ImageFormat ContentType { get; set; }
public bool EnableClientCache { get; set; }
public bool EnableServerCache { get; set; }
protected List<ImageTransform> ImageTransforms { get; }
public virtual bool IsReusable { get; }
public abstract ImageInfo GenerateImage(NameValueCollection parameters);
public void ProcessRequest(HttpContext context);
}
}
ImageTransforms? Hm...you can also setup a collection of ImageTransform objects into a little mini-image processing pipeline to do whatever you like.
Here we add a copyright watermark dynamically. The Transform is added in the constructor in this example.
public class TestCustomImages : ImageHandler {
public TestCustomImages()
{
this.ImageTransforms.Add(new CustomImageTransforms.ImageCopyrightTransform { Text = "Copyright Me! 2008" });
this.ContentType = System.Drawing.Imaging.ImageFormat.Png;
}
public override ImageInfo GenerateImage(NameValueCollection parameters) {
Bitmap pic = new Bitmap(200, 50);
Graphics gra = Graphics.FromImage(pic);
gra.Clear(Color.SkyBlue);
return new ImageInfo(pic);
}
}
The source for the CustomTransform, and for all the samples and the preview assembly that makes it all work is up on CodePlex now. If you've got ideas, find bugs, or think it's cool, leave a comment here and I'll make sure they get them. You can also leave bugs in the Issue Tracker on CodePlex.
Here's what the roadmap document says they've got planned...
- Add Item Templates for an Image Handler
- Providing parameter type inference for the handler instead of a Name Value Collection.
- Giving you control of transforms, caching inside of your Generate Image Method.
Does it work with ASP.NET MVC?
Gee, I dunno. Let's see. Remember that if you're using ASP.NET MVC with the WebFormsViewEngine, as long as there's no Postback, some Server Controls can still work. This just might, as it renders on the first load.
I added the ASHX handler file to my MVC project, referenced the DLL, made sure to register the tag prefix and it mostly worked. The design service isn't working, saying something about "could not be set on property ImageHandlerUrl," but I'm encourage I got this far. Let's encourage them to keep MVC in mind!
Cool. Have at it at CodePlex. No warranty express or implied.
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter

The general idea os:
BlogSvc.NET - The AtomPub Server for WCF and .NET
My 
