Introduction
Here, I want to share a nice way to display images on web pages using an HttpHandler. Using this method, we can hide an image's server mapped path from the user as in the image shown above. Also, the same image handler can be used to generate thumbnails of variable dimensions passed using the querystring.
Understanding the code
The heart of this generic image handler is the ImageHandler
class which implements the IHttpHandler
and IRequiresSessionState
interfaces.
IRequiresSessionState
specifies that the target HTTP handler requires read and write access to session-state values. This is a marker interface and has no methods.
The IHttpHandler
interface's ProcessesRequest
method is implemented in this handler where all the image processing logic goes. Every time the handler is invoked, the handler checks for parameters passed through the query string, generates the corresponding image response, and writes it to current context. For further requests of the same image, the response is saved in a hash table, in the session. The same image handler can be used for multiple groups of images. In this example, I have used it for two groups: User Images and Status Images. A Dictionary
object map
is used to map different image groups with the strict filename logic used here.
public void ProcessRequest(HttpContext context)
{
if (context.Request["id"] != null &&
context.Request["tName"] != null)
{
Dictionary<string,> map = new Dictionary<string,>();
map.Add("UserImage", "user");
map.Add("StatusImage", "status");
if (context.Request["xlen"] != null)
{
XLen = context.Request["xlen"].ToString();
}
if (context.Request["ylen"] != null)
{
YLen = context.Request["ylen"].ToString();
}
string id = context.Request["id"].ToString();
string tName = context.Request["tName"].ToString();
Hashtable ht;
if (context.Session[tName] != null)
{
ht = (Hashtable)context.Session[tName];
if (!ht.ContainsKey(id))
{
FileStream fInfo = new FileStream(context.Server.MapPath("images/" +
map[tName].ToString() + id + ".jpg"), FileMode.Open);
byte[] bFile ;
bFile = GenerateThumbnail(fInfo, XLen, YLen);
ht.Add(id, bFile);
fInfo.Close();
}
}
else
{
ht = new Hashtable();
FileStream fInfo = new FileStream(context.Server.MapPath("images/" +
map[tName].ToString() + id + ".jpg"), FileMode.Open);
byte[] bFile ;
bFile = GenerateThumbnail(fInfo, XLen, YLen);
ht.Add(id, bFile);
context.Session[tName] = ht;
fInfo.Close();
}
Byte[] arrImg = (byte[])ht[id];
context.Response.Clear();
context.Response.ContentType = "image/jpeg";
context.Response.BinaryWrite(arrImg);
context.Response.End();
}
}
A simple thumbnail generation routine is used to generate thumbnails of the desired size. It uses the System.Drawing.Image
class' GetThumbnailImage()
method to generate thumbnails.
private byte[] GenerateThumbnail(Stream fStream, string xLen, string yLen)
{
Image img = Image.FromStream(fStream);
Image thumbnailImage = img.GetThumbnailImage(int.Parse(xLen),int.Parse(yLen),
new Image.GetThumbnailImageAbort(ThumbnailCallback), IntPtr.Zero);
MemoryStream imageStream = new MemoryStream();
thumbnailImage.Save(imageStream, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] imageContent = new Byte[imageStream.Length];
imageStream.Position = 0;
imageStream.Read(imageContent, 0, (int)imageStream.Length);
return imageContent;
}
Using the code
The web application is informed of the HttpHandler using the web.config.
<add type="ImageHandlerLib.ImageHandler, ImageHandlerLib"
path="ImageHandler.aspx" verb="*" />
The default thumbnail size has been set as 110X110 in the ImageHandler
class. This dimension is used unless both the attributes are sent via the query string to the handler.
Displaying an image this way hides the server mapped path that we would normally use like "<img src="image/user1.jpg" />
, which gives away our directory structure of the virtual directory. Instead, we use a generic URL and pass parameters requesting specific images in the query string. The general format for queering any image using the above handler is:
src = "ImageHandler.aspx?tName=[groupname]&id=[idnumber]"
Scope
To further make the image handler's URLs secure so that nobody else can directly access your URLs in their own applications, you can implement your own security checking code in the beginning of the ProcessRequest
method.
Also, instead of the strict file naming logic (i.e., strict filename formats for image files) that I have used in this example, the code can be further customized to have file names of image files passed as query string parameters. That should make this image handler really generic. :)
History
B.E. in Information Technology
MCTS(.NET 2.0 )