Dynamically resize images in memory

Recently I was working on a project where I needed to have the ability to resize images, but not have the newly created image be saved to the filesystem.  I also didn't want to modify the original image, as the images needed to be kept in their original unmodified form.

After searching the blogs and forums, I came across some code that seemed to do exactly what I needed and then some.  Not only did it create the file in memory, but it also allowed me to specify the width and height, and maintained the aspect ratio of the original image.  What I came up with was an HTTP handler that allowed me to specify a filename, width, and height and have the server return an output stream containing the new image.  Additionally I added a key to the web.config that allowed me to specify the folder that the original images are stored (since this never changed) allowing me to only specify the filename in the calling code.  The resulting code works for both ASP.Net image controls and standard HTML image tags since the ImageUrl or SRC is set to a virtual path with 3 querystring values.

The code for my custom handler is as follows (note that my standard disclaimer found here applies as usual):

First, you need to the this to the <appSettings> section of the web.config, replacing the "Images\Test" with the folder that contains your image

<add key="ResizeHandlerInputFolder" value="Images\Test"/>

Second, add the httpHandler code to the handler section of your web.config (be sure to add it to the correct place depending on the version of IIS that you are using

<add name="PhotoResizeHandler" verb="*" path="*.image" type="PhotoHandler.Resize, PhotoHandler" />

Third, create a new class with the following code, modifying it as you see fit. 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Web;
using System.Drawing;
using System.Configuration;
using System.IO;

namespace PhotoHandler
{
    public class Resize : IHttpHandler
    {
        public bool IsReusable
        {
            get { return false; }
        }

        public void ProcessRequest(HttpContext context)
        {
            try
            {
                if (context.Request.QueryString["filename"] != null)
                {
                    if (context.Request.QueryString["width"] != null && context.Request.QueryString["height"] != null)
                    {
                        Image FullsizeImage = Image.FromFile(context.Server.MapPath(context.Request.ApplicationPath) + "\\" + ConfigurationManager.AppSettings["ResizeHandlerInputFolder"] + "\\" + context.Request.QueryString["filename"].ToString());
                        int NewWidth = int.Parse(context.Request.QueryString["width"].ToString());
                        int MaxHeight = int.Parse(context.Request.QueryString["height"].ToString());
                        // Prevent using images internal thumbnail                        
                        FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
                        FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);

                        if (FullsizeImage.Width  MaxHeight)
                        {
                            NewWidth = FullsizeImage.Width * MaxHeight / FullsizeImage.Height;
                            NewHeight = MaxHeight;
                        }

                        System.Drawing.Image NewImage = FullsizeImage.GetThumbnailImage(NewWidth, NewHeight, null, IntPtr.Zero);

                        using (MemoryStream ms = new MemoryStream()) 
                        {
                            if (Path.GetExtension(context.Request.QueryString["filename"].ToLower()) == ".jpg")
                            {
                                context.Response.ContentType = "image/jpg";
                                NewImage.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                            }
                            else if (Path.GetExtension(context.Request.QueryString["filename"].ToLower()) == ".gif")
                            {
                                context.Response.ContentType = "image/gif";
                                NewImage.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
                            }
                            else if (Path.GetExtension(context.Request.QueryString["filename"].ToLower()) == ".png")
                            {
                                context.Response.ContentType = "image/png";
                                NewImage.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
                            }
                            ms.WriteTo(context.Response.OutputStream); 
                        }
                        
                        FullsizeImage.Dispose();
                        NewImage.Dispose();
}
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
    }
}

To use the new handler, create a standard HTML image with the SRC set as a call to the .image extension. You'll need to pass in the 3 querystring parameters as well. An example of this is as follows:

<img src="Resize.image?filename=mypic.jpg&width=100&height=50" alt="" />

The result should be as seen below with my logo. The top image is the full-size image, and the bottom is the newly resize version:

Full-size logo

One last note is that the height that you specify isn't necessarily going to be the final height of the image, but the maximum height that the final image can be.  The code adjusts the height to maintain the aspect ratio depending on the width that you specify.  In my above example I specified a width of 200px and a height of 100px.  The resulting image is actually 200px wide by 48px high because the code also maintains the aspect ratio.

I hope this code helps someone.  Feel free to modify it as needed and use it in your own projects.


14. August 2014 16:44 by Admin | Comments (0) | Permalink