Serving Images on the Web
Take Control of How Images Are Displayed
October 30, 2009
CoreCoder
LANGUAGES: C#
ASP.NETVERSIONS: 2.0 | 3.5
Serving Images on the Web
Take Control of How Images Are Displayed
By Dino Esposito
Lastmonth I started an interesting discussion on how to serve images to thebrowser from within a Web application. I discussed HTTP handlers and created arelatively simple handler to extract and serve the bits of images stored in adatabase. This month, we ll tackle more sophisticated techniques to pre-processimages before they are served to the client. Images are still plain-old JPG orGIF files, and images are still stored in some folder on the Web server.However, you can find out ways to wrap them in a piece of custom code thatultimately controls how bits are retrieved and which bits are actually served.
The Default Case
Images are static files; as such, they are served directlyby IIS without the involvement of any other external ISAPI component. To expeditethings, IIS normally takes on the task of serving requests for static resourcessuch as JPG and HTML files. These resources don t normally require any extrawork. All that is required is that some module takes the challenge of resolvingthe URL, locating the server file, extracting the contents, and serving it upto the client browser flagged with the proper content type header. IIS has beendoing this since its first version. Is there any relapse on ASP.NETdevelopment?
Among other things, having IIS to serve images means thatimage files are kept well off the realm and the context of an ASP.NETapplication. For example, it means you can t associate an image file with thesecurity rules of an application. No matter that you place the image file in aprotected folder that requires authentication; as long as a page links an imageby name, the bits of the images are always successfully retrieved and served.The same happens if a user references the image from the browser s address bar.No ASP.NET protection will work to control who s physically requesting theimage.
Do you really need to protect your images? Well, itdepends on the nature and purpose of the images. But the real question to beasked is a slightly different one. That is, do you really need to add somecustom logic to the default process that downloads images over the Web?
In the vast majority of scenarios you d likely take the free service provided by IIS. When this is not enough and you need more power, thefirst thing to do is delegate the control of some image extensions (i.e., JPG)to a custom module registered with IIS. As you ll learn in a moment, the wayyou do this is different with IIS 6 and IIS 7. Let s review a few realisticscenarios where you need more control over the image download process.
Serving Dynamically Created Images
A lot of financial Web sites return information to theirusers via images. On the other hand, isn t it true that an image is worthdozens of words? Web-deployed charts are often dynamically generated on theserver and served to the browser as a stream of bytes. Charts are ultimatelyJPG images, but there s no static JPG file uploaded on the server. The image isgenerated on demand and incorporates information read dynamically from someexternal source. How would you create images dynamically? Or, more in general,how would you pre-process existing images before display?
Creating images on the fly or editing existing imagesbefore display are two faces of the same coin. In both situations, you need agraphical API to edit a bitmap. In ASP.NET, such an integrated graphic enginethat provides an object model for image generation is GDI+.
GDI+ is the graphic engine of Windows XP also madeavailable for other 32-bit and 64-bit platforms such as Windows 200x Server andWindows Vista. The .NET Framework encapsulates the key GDI+ functionalities ina handful of managed classes. You use these classes to create or edit images inmemory.
The first step for a GDI+ application is creating, orobtaining, a new graphic context represented by an instance of the Graphicsclass. A new Graphics object can be obtained in various ways, but theGraphics.FromImage method is the only creator method that makes sense forASP.NET applications. The following code snippet shows how to create a graphiccontext:
Bitmap bmp = new Bitmap(100, 100);
Graphics g = Graphics.FromImage(bmp);
Any graphic primitives that operates on the Graphicsobject will affect the underlying Bitmap object. When you re done with thegraphics work, save the Bitmap object to a number of formats, including PNG,JPG, and GIF. The Bitmap class also supplies methods to rotate and flip theimage and, more interestingly for our purposes, it features a constructor thatinstantiates a Bitmap object from an existing file:
Bitmap bmp = new Bitmap(file);
In this latter case, any successive graphic work is doneover a memory bitmap that represents a copy of a server image file.
Suppose now that you want to add a copyright note to allimages served from your Web site. You must reference these images in anon-standard way, avoiding the traditional *.jpg extension. You must turn to acustom URL and use a URL that is bound to a proper HTTP handler. Figure 1 showsa portion of an HTTP handler that adds a copyright note to the bottom-rightcorner of any image that is referenced through it.
public class DynamicImageHandler : IHttpHandler
{
public voidProcessRequest(HttpContext context)
{
// Process the URLparam
object o1 =context.Request["url"];
if (o1 == null)
{
context.Response.End();
return;
}
string file =context.Server.MapPath((string)o1);
if(!IsImageFile(file))
{
context.Response.End();
return;
}
// Read copyrightstring from AppSettings
string msg =
ConfigurationManager.AppSettings["CopyrightForImages"];
if(File.Exists(file))
{
Bitmap bmp =AddCopyright(file, msg);
context.Response.ContentType = "image/jpeg";
bmp.Save(context.Response.OutputStream,
ImageFormat.Jpeg);
bmp.Dispose();
}
else
context.Response.End();
}
public bool IsReusable
{
get { return true; }
}
}
Figure 1: An HTTPhandler for adding a copyright note to images.
You may not be able to associate this handler with the*.jpg extension; not until IIS 7 and Windows 2008 Server is available inproduction. Consequently, you resort to an ASHX handler and use it to referencethe image wherever an tag is required. Here s an example:
Figure 2 shows some GDI+ code that reads a copyright notefrom the web.config file and writes that out to the displayed image (see Figure3). If the user right-clicks on the image and saves a local copy of the image,it gets the modified copy of the image with the copyright text on it.
Bitmap AddCopyright(string file, string msg)
{
// Load the file andcreate the graphics
Bitmap bmp = newBitmap(file);
Graphics g =Graphics.FromImage(bmp);
// Define text alignment
StringFormat strFmt = newStringFormat();
strFmt.Alignment =StringAlignment.Center;
// Create brushes for thebottom writing
// (green text on blackbackground)
SolidBrush btmForeColor =new SolidBrush(Color.PaleGreen);
SolidBrush btmBackColor =new SolidBrush(Color.Black);
// To calculate writingcoordinates, obtain the size of
// the text given fonttypeface and size
Font btmFont = newFont("Verdana", 7);
SizeF textSize = newSizeF();
textSize =g.MeasureString(msg, btmFont);
// Calculate the outputrectangle and fill
float x =((float)bmp.Width - textSize.Width - 3);
float y =((float)bmp.Height - textSize.Height - 3);
float w = ((float)x +textSize.Width);
float h = ((float)y +textSize.Height);
RectangleF textArea = newRectangleF(x, y, w, h);
g.FillRectangle(btmBackColor, textArea);
// Draw the text and freeresources
g.DrawString(msg,btmFont, btmForeColor, textArea);
btmForeColor.Dispose();
btmBackColor.Dispose();
btmFont.Dispose();
g.Dispose();
return bmp;
}
Figure 2: Adding acopyright note to a JPG image.
Figure 3: A dynamically modifiedimage.
Can we conclude that we solved the issue of having ourcopyright on any image in our Web site that is referenced through the handler?Well, not exactly. The main flipside of this approach is that it all works aslong as we pass through the handler. If a user figures out the exact serverpath to the image and requests or links that path directly, the handler is wellbypassed and no copyright note will ever appear.
Modify the Image Extension
If you want to always serve dynamically modified images,then you need to find a way to bypass IIS. In IIS 6, all you can do is renameimages to a custom extension for example, *.jpgx that IIS doesn t know. Atthe same time, you tell IIS that ASP.NET knows how to deal with thoseresources. You do this through the MMC snap-in of the IIS 6 manager. Go to theConfiguration screen and add the *.jpgx extension to the list. To make ASP.NETserve the request, you must bind the resource to the aspnet_isapi.dllextension. You can simply copy all the existing settings for the ASPX resource.
At this point, a request for a JPGX resource will beredirected to your application. A change in the web.config file is required tobind JPGX resources to the specified handler:
"Samples.DynamicImageHandler"/>
The bottom line is that you are no longer using JPG files,neither directly nor indirectly through the dynimage.ashx handler. Any requestsfor a JPGX resource passes through your handler. All images served by yourapplication with that extension will display the proper copyright note, evenwhen referenced from an external site.
Force IIS 7 to Do It Your Way
In IIS 7, you have more control over any types ofresources your applications use. For example, IIS 7 enables you to register ahandler for just any resource, including static files that would otherwise beautomatically served by the system. An ASP.NET application hosted under IIS 7can include a new section in its web.config file. Ignored under IIS 6, the newsection is named system.webServer. Here s an excerpt:
type="Samples.DynImageHandler" />
The section is the root elementfor the IIS 7.0 configuration. It contains elements, such as ,that configure settings used by the Web server engine. The sectionlists all HTTP handlers that apply at the IIS 7 level; that is, before yourrequest makes its way to the ASP.NET runtime. Put another way, any HTTP handlerregistered in the section of your application istriggered for whatever requests that hits IIS regarding your application. Withthe previous configuration in place, JPG files are pre-processed by the dynamicimage handler without the need of using a different endpoint or a modified URL.In this way, your JPG files are stored on the server in their original form,but are served to any client with a copyright note.
Conclusion
HTTP handlers allow a finer control over resources and arethe perfect tool to employ whenever you need to add some custom logic aroundthe processing of a Web resource. In IIS 6, though, there are some resources (specifically,static files such as HTML and JPG) that are natively served by IIS and neverreach the context of ASP.NET where, ultimately, HTTP handlers live. In IIS 7,this limitation is removed and you can define HTTP handlers that operate at theIIS level for all requests that pertain to your application. IIS 7 ships forserver environments as part of Windows 2008 Server, but can be tested right nowthrough Windows Vista.
Dino Espositospecializes mainly in ASP.NET, AJAX,and RIA solutions and is the author of the upcoming Programming ASP.NET 3.5 Core Reference (Microsoft Press, 2008).He also wrote Introducing ASP.NET AJAX,always for Microsoft Press. Late-breaking news is available at http://weblogs.asp.net/despos.
About the Author
You May Also Like