Serving Images on the Web

Take Control of How Images Are Displayed

CoreCoder

LANGUAGES: C#

ASP.NET VERSIONS: 2.0 | 3.5

 

Serving Images on the Web

Take Control of How Images Are Displayed

 

By Dino Esposito

 

Last month I started an interesting discussion on how to serve images to the browser from within a Web application. I discussed HTTP handlers and created a relatively simple handler to extract and serve the bits of images stored in a database. This month, we ll tackle more sophisticated techniques to pre-process images before they are served to the client. Images are still plain-old JPG or GIF 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 that ultimately controls how bits are retrieved and which bits are actually served.

 

The Default Case

Images are static files; as such, they are served directly by IIS without the involvement of any other external ISAPI component. To expedite things, IIS normally takes on the task of serving requests for static resources such as JPG and HTML files. These resources don t normally require any extra work. All that is required is that some module takes the challenge of resolving the URL, locating the server file, extracting the contents, and serving it up to the client browser flagged with the proper content type header. IIS has been doing this since its first version. Is there any relapse on ASP.NET development?

 

Among other things, having IIS to serve images means that image files are kept well off the realm and the context of an ASP.NET application. For example, it means you can t associate an image file with the security rules of an application. No matter that you place the image file in a protected folder that requires authentication; as long as a page links an image by 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 the image.

 

Do you really need to protect your images? Well, it depends on the nature and purpose of the images. But the real question to be asked is a slightly different one. That is, do you really need to add some custom 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, the first 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 way you do this is different with IIS 6 and IIS 7. Let s review a few realistic scenarios where you need more control over the image download process.

 

Serving Dynamically Created Images

A lot of financial Web sites return information to their users via images. On the other hand, isn t it true that an image is worth dozens of words? Web-deployed charts are often dynamically generated on the server and served to the browser as a stream of bytes. Charts are ultimately JPG images, but there s no static JPG file uploaded on the server. The image is generated on demand and incorporates information read dynamically from some external 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 images before display are two faces of the same coin. In both situations, you need a graphical API to edit a bitmap. In ASP.NET, such an integrated graphic engine that provides an object model for image generation is GDI+.

 

GDI+ is the graphic engine of Windows XP also made available for other 32-bit and 64-bit platforms such as Windows 200x Server and Windows Vista. The .NET Framework encapsulates the key GDI+ functionalities in a handful of managed classes. You use these classes to create or edit images in memory.

 

The first step for a GDI+ application is creating, or obtaining, a new graphic context represented by an instance of the Graphics class. A new Graphics object can be obtained in various ways, but the Graphics.FromImage method is the only creator method that makes sense for ASP.NET applications. The following code snippet shows how to create a graphic context:

 

Bitmap bmp = new Bitmap(100, 100);

Graphics g = Graphics.FromImage(bmp);

 

Any graphic primitives that operates on the Graphics object will affect the underlying Bitmap object. When you re done with the graphics 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 the image and, more interestingly for our purposes, it features a constructor that instantiates a Bitmap object from an existing file:

 

Bitmap bmp = new Bitmap(file);

 

In this latter case, any successive graphic work is done over a memory bitmap that represents a copy of a server image file.

 

Suppose now that you want to add a copyright note to all images served from your Web site. You must reference these images in a non-standard way, avoiding the traditional *.jpg extension. You must turn to a custom URL and use a URL that is bound to a proper HTTP handler. Figure 1 shows a portion of an HTTP handler that adds a copyright note to the bottom-right corner of any image that is referenced through it.

 

public class DynamicImageHandler : IHttpHandler

{

  public void ProcessRequest(HttpContext context)

  {

    // Process the URL param

    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 copyright string 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 HTTP handler 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 in production. Consequently, you resort to an ASHX handler and use it to reference the image wherever an tag is required. Here s an example:

 

 

Figure 2 shows some GDI+ code that reads a copyright note from the web.config file and writes that out to the displayed image (see Figure 3). 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 and create the graphics

 Bitmap bmp = new Bitmap(file);

 Graphics g = Graphics.FromImage(bmp);

 // Define text alignment

 StringFormat strFmt = new StringFormat();

 strFmt.Alignment = StringAlignment.Center;

 // Create brushes for the bottom writing

 // (green text on black background)

 SolidBrush btmForeColor = new SolidBrush(Color.PaleGreen);

 SolidBrush btmBackColor = new SolidBrush(Color.Black);

 // To calculate writing coordinates, obtain the size of

 // the text given font typeface and size

 Font btmFont = new Font("Verdana", 7);

 SizeF textSize = new SizeF();

 textSize = g.MeasureString(msg, btmFont);

 // Calculate the output rectangle 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 = new RectangleF(x, y, w, h);

 g.FillRectangle(btmBackColor, textArea);

 // Draw the text and free resources

 g.DrawString(msg, btmFont, btmForeColor, textArea);

 btmForeColor.Dispose();

 btmBackColor.Dispose();

 btmFont.Dispose();

 g.Dispose();

 return bmp;

}

Figure 2: Adding a copyright note to a JPG image.

 


Figure 3: A dynamically modified image.

 

Can we conclude that we solved the issue of having our copyright 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 as long as we pass through the handler. If a user figures out the exact server path to the image and requests or links that path directly, the handler is well bypassed 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 rename images to a custom extension for example, *.jpgx that IIS doesn t know. At the same time, you tell IIS that ASP.NET knows how to deal with those resources. You do this through the MMC snap-in of the IIS 6 manager. Go to the Configuration screen and add the *.jpgx extension to the list. To make ASP.NET serve the request, you must bind the resource to the aspnet_isapi.dll extension. You can simply copy all the existing settings for the ASPX resource.

 

At this point, a request for a JPGX resource will be redirected to your application. A change in the web.config file is required to bind 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 requests for a JPGX resource passes through your handler. All images served by your application with that extension will display the proper copyright note, even when referenced from an external site.

 

Force IIS 7 to Do It Your Way

In IIS 7, you have more control over any types of resources your applications use. For example, IIS 7 enables you to register a handler for just any resource, including static files that would otherwise be automatically served by the system. An ASP.NET application hosted under IIS 7 can include a new section in its web.config file. Ignored under IIS 6, the new section is named system.webServer. Here s an excerpt:

 

  

    

      type="Samples.DynImageHandler" />

  

 

The section is the root element for the IIS 7.0 configuration. It contains elements, such as , that configure settings used by the Web server engine. The section lists all HTTP handlers that apply at the IIS 7 level; that is, before your request makes its way to the ASP.NET runtime. Put another way, any HTTP handler registered in the section of your application is triggered for whatever requests that hits IIS regarding your application. With the previous configuration in place, JPG files are pre-processed by the dynamic image 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 are the perfect tool to employ whenever you need to add some custom logic around the 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 never reach 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 the IIS level for all requests that pertain to your application. IIS 7 ships for server environments as part of Windows 2008 Server, but can be tested right now through Windows Vista.

 

Dino Esposito specializes 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.

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish