<%@ WebHandler Language="C#" Class="ImageHandler" %> using System; using System.Web; /// /// www.DotNetManiac.info /// November 14 2005 - [created] /// January 16 2005 - [revised] /// February 22 2006 - [revised] /// May 08 2006 - [revised] /// August 18 2007 - [revised] /// August 12 2009 - [revised] /// November 24 2009 - [revised] /// December 15 2009 - [revised] /// /// Creates a dynamic image and returns it in the outputstream for an img src /// This takes away the overhead of using an aspx page. Commonly used for /// creating thumbnail images or zooming in or out of images. /// This implimentation works with JPG images only. /// /// Max image size is set to avoid performance issues. /// /// If constrain proportions is set to true, then image will scale based on /// requested width. Otherwise image will be forced to requested dimensions /// which might produce a slightly distorted image. /// /// Update on May 08 2006 /// Allows constrain proportions to be used. If constrain /// proportions is set to true, then image will scale based on /// requested width. Otherwise image will be forced to requested dimensions /// which might produce a slightly distorted image. /// /// Update August 18 2006 - ported to C# /// changed the method of resizing to use a Graphics object which produces /// a much better quality image regardless of dimensions while only having a /// slightly larger image size than the bitmap.GetThumbnailImage method. /// Also general code cleanup /// /// Update August 12 2009 /// Code was reorganized for better maintainability. Use of USING blocks were added /// for bitmap and graphic objects. /// /// Update November 24 2009 - Added ability to rotate images 90, 180, and 270 degrees. /// /// Update December 15 2009 - Fixed a bug that didn't resize portrait images properly. /// public class ImageHandler : IHttpHandler { // incoming query string variables private string imagePath = string.Empty; // path= virtual path required private string imageWidth = "0"; // w= 0 means use original private string imageHeight = "0"; // h= private string imageQuality = "0"; // q= private string constrainProportions = "true"; // cp= true or false private string rotation = "0"; // r= rotation in degrees, optional, 0 is default. private const Int32 maxQuality = 100; private const Int32 minQuality = 30; private const string imageNotFound = "~/App_Images/image_not_found.jpg"; private const string mimeType = "image/jpeg"; public void ProcessRequest(HttpContext context) { // get query string parameters imagePath = context.Request.QueryString["path"]; imageWidth = context.Request.QueryString["w"]; imageHeight = context.Request.QueryString["h"]; imageQuality = context.Request.QueryString["q"]; constrainProportions = context.Request.QueryString["cp"]; rotation = context.Request.QueryString["r"]; // sets the HTTP MIME type of the output stream. // jpeg is default context.Response.ContentType = mimeType; // clear all content output from the buffer stream context.Response.Clear(); // response is cacheable by clients and shared (proxy) caches context.Response.Cache.SetCacheability(HttpCacheability.Public); // Buffer response so that page is sent // after processing is complete. context.Response.BufferOutput = true; if (System.IO.File.Exists(HttpContext.Current.Server.MapPath(imagePath))) { imagePath = HttpContext.Current.Server.MapPath(imagePath); } else { // displays an empty image holder or make sure you have a not found image imageQuality = "100"; imagePath = HttpContext.Current.Server.MapPath(imageNotFound); } Int32 originalWidth = 0; Int32 originalHeight = 0; Int32 newWidth = 0; Int32 newHeight = 0; Int64 quality = 0; // set the quality of the jpeg image returned.. 30 (low) - 100 (high) if (Int64.TryParse(imageQuality, out quality)) { if (quality > maxQuality) { quality = maxQuality; } if (quality < minQuality) { quality = minQuality; } } else { quality = maxQuality; } // ENCODING System.Drawing.Imaging.Encoder encoder = System.Drawing.Imaging.Encoder.Quality; System.Drawing.Imaging.EncoderParameter encoderParameter = new System.Drawing.Imaging.EncoderParameter(encoder, quality); // create an array with one parameter; quality System.Drawing.Imaging.EncoderParameters codecParams = new System.Drawing.Imaging.EncoderParameters(1); codecParams.Param[0] = encoderParameter; // Gets the codecs for this image type (jpeg) System.Drawing.Imaging.ImageCodecInfo codecInfo = getEncoderInfo(); // Create a bitmap to hold new image, uses Bitmap.GetThumbnailImage using (System.Drawing.Bitmap bitmapOriginal = new System.Drawing.Bitmap(imagePath)) { originalWidth = bitmapOriginal.Width; originalHeight = bitmapOriginal.Height; Int32.TryParse(imageWidth, out newWidth); Int32.TryParse(imageHeight, out newHeight); if (newWidth > originalWidth) { newWidth = originalWidth; } if (newHeight > originalHeight) { newHeight = originalHeight; } // Constrain Proportions provides scaling by width // False by default which forces width and height - when exact size required if (!string.IsNullOrEmpty(constrainProportions) && constrainProportions.Equals("true", StringComparison.OrdinalIgnoreCase)) { newWidth = Convert.ToInt32(imageWidth); Double scaleFactor = 0.0; // scale the image based on the width if (originalWidth > originalHeight) { // landscape Int32 largestDimension = (Math.Max(originalWidth, originalHeight)); scaleFactor = ((Double)newWidth / (Double)largestDimension); } else { // portrait Int32 smallestDimension = (Math.Min(originalWidth, originalHeight)); scaleFactor = ((Double)newWidth / (Double)smallestDimension); } newHeight = Convert.ToInt32((originalHeight * scaleFactor)); } // Create the new bitmap image using (System.Drawing.Bitmap bitmapNew = new System.Drawing.Bitmap(newWidth, newHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb)) { // use the same resolution bitmapNew.SetResolution(bitmapOriginal.HorizontalResolution, bitmapOriginal.VerticalResolution); // Create the graphics object to draw the old bitmap on the new sized bitmap. using (System.Drawing.Graphics graphic = System.Drawing.Graphics.FromImage(bitmapNew)) { // resize using the highest possible quality for best results graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; graphic.DrawImage(bitmapOriginal, new System.Drawing.Rectangle(0, 0, newWidth, newHeight), // destination new System.Drawing.Rectangle(0, 0, originalWidth, originalHeight), //source System.Drawing.GraphicsUnit.Pixel); //using pixels } // Rotate the bitmap switch (Convert.ToInt32(rotation)) { case 90: bitmapNew.RotateFlip(System.Drawing.RotateFlipType.Rotate90FlipNone); break; case 180: bitmapNew.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone); break; case 270: bitmapNew.RotateFlip(System.Drawing.RotateFlipType.Rotate270FlipNone); break; default: // always show as original bitmapNew.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipNone); break; } // context.Response.OutputStream enables binary output to the outgoing HTTP content body. // codecInfo is the image type (jpeg) // codecParams is the quality bitmapNew.Save(context.Response.OutputStream, codecInfo, codecParams); } } } /// /// Return the codec info for jpeg images /// /// /// private System.Drawing.Imaging.ImageCodecInfo getEncoderInfo() { System.Drawing.Imaging.ImageCodecInfo[] encoders; encoders = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders(); Int32 i = 0; while (i < encoders.Length) { if (encoders[i].MimeType == mimeType) { return encoders[i]; } i++; } return null; } public bool IsReusable { get { return false; } } }