Hullo once again to you all 🙂
Sorry, been a busy February for me, hence a month or so since my last post, but I’m back with another of those useful snippets of code that came about due to a question on Lidnug (For those of you not yet Familiar I’m one of the group managers in the Linked.NET users group on Linked IN, you can find the Link in my blogroll/links).
The Question this time was how to do images Dynamically. Now we all know since the beginning of .NET we’ve had access to a rather nice (if at times tricky) API called GDI+. This API has made drawing graphics in C# a breeeze.
The problem you have, is that beacuse of how an ASP.NET page is processed, you cant just create and spit out a bitmap in the middle of a page, at least not in the same manner that you can in a win-forms application.
What you can do however, is use an old trick that goes back to the days of Perl & CGI based scripts, and use an independent asp script to produce only the graphic you require, you then use this script in the same way you would use a normal image.
This was used to huge effect for custom buttons, banners, graphical headlines and lot’s of other nice effects before things like AJAX became available, and can if used correctly produce some really nice graphics. If you then stop to consider into days age using AJAX and Timers and Partial rendering, it’s not difficult to realise that you could do real-time graphs, animations and a lot of other things.
So how does it work?
Well to be honest it’s not rocket science, it’s all about making sure 2 things happen:
1) NO Output can be generated from your ASPX page, everything must be done in the code behind
2) You must absolutely make sure that you send the correct mime type, for images this will be “image/jpeg”, “image/png”, “image/gif” or some other type.
Remember also that this technique can also be used to generate other types of content to as I previously demonstrated in my Blog article on creating Phone Directories Here.
Remember however, that there is also a performance penalty to be had, if you use this method on a heavily used site, then your hit count is going to be way way higher beacuse your also going to get page hits recorded for each button drawn, and if you use the method to generate roll over buttons then you can easily double that. If you also have a host that has a clause about making the server work too hard and not just bandwidth and Data as usual, then you may also get penalised beacuse of the extra work this will make the .NET run time use.
Once your happy that you’ve covered all the exits, and got the mime type correct then it’s simply just a matter of generating the content you want in the page load event, remember also that there is no forms or anything like that so you can’t do this on a postback.
To generate the output, the first thing you need to do is to empty the aspx page and insert the correct mime type, you should have NOTHING in your aspx except the following
<%@ Page Language=”C#” Debug=”true” AutoEventWireup=”true” CodeFile=”DynamicImage.aspx.cs” Inherits=”DynamicImage” ContentType=”image/jpeg” %>
as you can see above, I’ve set the content type to image/jpeg, you can set this to ANY mime type you want to generate.
Once you have that then all the rest of your code needs to be in your code behind file, the first thing you need to do is create a bitmap to draw on, how you do this depends on weather or not your drawing from scratch, or re-using an existing image.
If your drawing from scratch then you need to do something similar to the following:
Bitmap outputBitmap = new Bitmap(xsize,ysize);
Graphics outputCanvas = Graphics.FromImage(outputBitmap);
If your reusing an existing image then you need something like this:
System.Drawing.Image templateImage = System.Drawing.Image.FromFile(Server.MapPath(“images/blankbutton.jpg”));
Graphics outputCanvas = Graphics.FromImage(templateImage);
Be careful however if your re-using existing graphics as there is a big gotcha here, IF your re-using an indexed graphics format such as GIF or 8bpp PNG, Tiff and some others you’ll get an exception telling you that Index formats cannot have a Graphics context assigned to them.
Quite why the .NET designers chose to do this no one seems to know, however if you do get this then you can very simply get around it, by creating a new Image, and the drawing the original image to it as follows:
System.Drawing.Image templateImage = System.Drawing.Image.FromFile(Server.MapPath(“images/blankbutton.gif”));
Bitmap tempImage = new Bitmap(templateImage.Width, templateImage.Height);
Graphics outputCanvas = Graphics.FromImage(tempImage);
outputCanvas.DrawImage(templateImage, 0, 0);
If your not re-using a graphic then you can get your graphics context simply by doing the following:
Graphics outputCanvas = Graphics.FromImage(outputBitmap);
Once you have your graphics (in this case outputCanvas) then you can simply use existing GDI+ graphics commands to draw onto it.
SolidBrush myBrush = new SolidBrush(Color.Red);
SolidBrush backgroundBrush = new SolidBrush(Color.White);
outputCanvas.FillRectangle(backgroundBrush, 0, 0, 100, 100);
outputCanvas.FillRectangle(brushOne, 0, 50, 50, 50);
I’m not going to go into the details of the GDI+ calls as they can all be found in the MSDN documentation with reasonable ease.
Once you’ve drawn all your graphics, then you can return the image to the webserver by simply saving to the output stream as follows:
Response.ContentType = “image/jpeg”;
Notice we save from the in memory IMage and NOT the graphics canvas, it’s important to remember this beacuse if you create a temporary image as described above, then you need to invoke save on that and NOT on the original image that you loaded in.
However once you navigate the few traps that are there then you can use the technique to do all sorts of neat things.
As an example, I have an app that redraws a graph of network activity every 30 seconds on a partial postback using the ASP.NET AJAX controls, and it works well, I’ve also used the technique for miniture in page bar graphs and other useful goodies.
Do however heed the warnings, It can seriously degrade your app if there is a lot of processing to do and a lot of visitors to your site. As always Iv’e created a demo project which you can download from my sky drive here
If you get stuck or have any questions then the original thread on Lidnug can be found here by all means feel free to drop in and pay us a visit.
Happy Graphics Drawing