"How to dynamically resize images" by CMSN Software Tutorials, shows you how to resize and cache images dynamically. The logic is to pass the image size as parameters and based on the parameters we generate a dynamic image. Dynamic image will be cache on client browser, server level and application level.
In the previous tutorial of CMSN Software Tutorials "How to Compress Css and JavaScript Runtime", we explained how to compress, combined, compact and cache Style Sheets and JavaScript files.
//----------------------------------------------------------------------- // <copyright file="DynamicImage.ashx.cs" company="CMSN Software"> // Copyright © 2011 CMSN Software // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see http://www.gnu.org/licenses. // </copyright> //----------------------------------------------------------------------- namespace CMSN.Software.Tutorials.HowToDynamicallyResizeImages { using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; using System.Web; using System.Web.Caching; /// <summary> /// Resize images dynamically. /// </summary> public class DynamicImage : IHttpHandler { /// <summary> /// Default cache duration /// </summary> private static readonly TimeSpan CacheDuration = TimeSpan.FromDays(30); /// <summary> /// Gets a value indicating whether another request can use the /// <see cref="T:System.Web.IHttpHandler"/> instance. /// </summary> /// <returns> /// true if the <see cref="T:System.Web.IHttpHandler"/> instance is reusable; otherwise, false. /// </returns> public bool IsReusable { get { return false; } } /// <summary> /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the /// <see cref="T:System.Web.IHttpHandler"/> interface. /// </summary> /// <param name="context">An <see cref="T:System.Web.HttpContext"/> object that provides references to the /// intrinsic server objects (for example, Request, Response, Session, and Server) /// used to service HTTP requests. /// </param> public void ProcessRequest(HttpContext context) { string cacheKeyName = context.Request.Url.PathAndQuery; string imagePath = context.Server.MapPath(context.Request.Url.LocalPath); string imageExtention = Path.GetExtension(imagePath); string contentType = string.Empty; byte[] imageFileContent; ImageFormat imageFormat = null; switch (imageExtention) { case ".png": imageFormat = ImageFormat.Png; contentType = "image/png"; break; case ".jpg": case ".jpeg": case ".jpe": imageFormat = ImageFormat.Jpeg; contentType = "image/jpeg"; break; case ".bmp": imageFormat = ImageFormat.Bmp; contentType = "image/bmp"; break; case ".gif": imageFormat = ImageFormat.Gif; contentType = "image/gif"; break; default: break; } context.Response.ContentType = contentType; if (context.Cache[CacheKey(cacheKeyName)] != null) { imageFileContent = context.Cache[CacheKey(cacheKeyName)] as byte[]; } else { int imageWidth = 0; int imageHeight = 0; if (!string.IsNullOrEmpty(context.Request["w"])) { if (!int.TryParse(context.Request["w"], out imageWidth)) { imageWidth = 0; } } if (!string.IsNullOrEmpty(context.Request["h"])) { if (!int.TryParse(context.Request["h"], out imageHeight)) { imageHeight = 0; } } Image originalImage; if (File.Exists(imagePath)) { originalImage = Image.FromFile(imagePath); } else { originalImage = new Bitmap(100, 100); } if (imageWidth > 0 || imageHeight > 0) { if (imageHeight == 0 && imageWidth > 0) { imageHeight = originalImage.Height * imageWidth / originalImage.Width; } if (imageWidth == 0 && imageHeight > 0) { imageWidth = originalImage.Width * imageHeight / originalImage.Height; } } else { imageHeight = originalImage.Height; imageWidth = originalImage.Width; } using (Bitmap newImage = new Bitmap(originalImage, imageWidth, imageHeight)) { Graphics generatedImage = Graphics.FromImage(newImage); generatedImage.InterpolationMode = InterpolationMode.HighQualityBicubic; generatedImage.SmoothingMode = SmoothingMode.AntiAlias; generatedImage.CompositingQuality = CompositingQuality.HighQuality; generatedImage.DrawImage(originalImage, 0, 0, newImage.Width, newImage.Height); // make a memory stream to work with the image bytes using (MemoryStream imageStream = new MemoryStream()) { // put the image into the memory stream newImage.Save(imageStream, imageFormat); // make byte array the same size as the image byte[] imageContent = new byte[imageStream.Length]; // rewind the memory stream imageStream.Position = 0; // load the byte array with the image imageStream.Read(imageContent, 0, (int)imageStream.Length); // return byte array to caller with image type imageFileContent = imageContent; using (CacheDependency dependency = new CacheDependency(imagePath)) { context.Cache.Insert( CacheKey(cacheKeyName), imageContent, dependency, System.Web.Caching.Cache.NoAbsoluteExpiration, CacheDuration); } } } originalImage.Dispose(); } SetResponseCache(context.Response, new string[1] { imagePath }); context.Response.BinaryWrite(imageFileContent); } /// <summary> /// Generate unique Cache key. /// </summary> /// <param name="key">The cache key.</param> /// <returns>Generated unique Cache key</returns> protected static string CacheKey(string key) { return "DynamicImage." + key; } /// <summary> /// Sets the response cache. /// </summary> /// <param name="response">The response.</param> /// <param name="files">The files.</param> protected static void SetResponseCache(HttpResponse response, string[] files) { response.AddFileDependencies(files); HttpCachePolicy browserCache = response.Cache; DateTime modifiedTime = DateTime.Now; browserCache.SetCacheability(HttpCacheability.ServerAndPrivate); browserCache.VaryByParams["w"] = true; browserCache.VaryByParams["h"] = true; browserCache.VaryByParams["v"] = true; browserCache.SetOmitVaryStar(true); browserCache.SetExpires(modifiedTime.AddDays(7)); browserCache.SetValidUntilExpires(true); browserCache.SetLastModified(modifiedTime); browserCache.SetETagFromFileDependencies(); browserCache.SetLastModifiedFromFileDependencies(); } } }
we need to pass the parameters to the image for image width "w", image height "h" and file version "v". Based on those parameters dynamic image will be generated. After generating the resized image it will be cached on the client browser, server level and the application level. If we want to invalidate the cache, we can simply change the value of the parameter "v".
<configuration> <system.web> <compilation debug="true" targetFramework="4.0" /> <httpHandlers> <add verb="*" path="*.png,*.jpg,*.jpeg,*.gif,*.bmp" type="CMSN.Software.Tutorials.HowToDynamicallyResizeImages.DynamicImage,HowToDynamicallyResizeImages"/> </httpHandlers> </system.web> <system.webServer> <handlers> <add verb="*" path="*.png,*.jpg,*.jpeg,*.gif,*.bmp" name="DynamicImage" type="CMSN.Software.Tutorials.HowToDynamicallyResizeImages.DynamicImage,HowToDynamicallyResizeImages"/> </handlers> <validation validateIntegratedModeConfiguration="false"/> </system.webServer> </configuration>
In above configuration sample you can understand how to bind the asp.net Generic Web handler file to the custom file format. Here we bind the asp.net Generic Web handler to all the supporting image formats. Any request for those file format will be redirected to the asp.net Generic Web handler. For more information on binding the asp.net Generic Web handler to custom file format see How to: Configure an HTTP Handler Extension in IIS
http://localhost/Images/msdn.png?w=300&h=149 http://localhost/Images/msdn.png?w=300 http://localhost/Images/msdn.png?h=149 http://localhost/Images/msdn.png
In the first method generated image size will be width = 300 and height = 149
Second method generates the image on width = 300 and height based on the image aspect ratio.
Third sample generates the image height = 149 and width based on the image aspect ratio
Next one will return the image on original size.
We can pass the parameter "v" with any of above. value of the "v" will determine the cached file version.
2 comments:
Post a Comment