C# / .NETDevOpsMisc
C# / .NET
C# Thumbnail
Alexandru Puiu
Alexandru Puiu
September 24, 2012
1 min

In this tutorial I’ll share how I create a c# thumbnail for each photo on our websites, and keep track of how many different sizes I need to use, while keeping images small for efficient load time, and efficient for server load. I will attach the Thumbnailer class at the end of the post. The thumbnailer can handle fixed width & height risize/crop, proportional resizing, width & height constraint resizing. The Thumbnailer can be used directly as an IHttpHandler or as a helper class for for another handler in your project.

The first thing we like to do in our projects is to create a route for all the images on the website, so we add

_routes.Add("PhotosRoute", new Route("photos/{size}/{photoUrl}", new PhotoRouteHandler()));

Notice, this way all photos are contained within a single path, and you can change the size or url of a photo, and allow the browser to cache it.

And now, to write the IRouteHandler for the above route. You’ll need to import the following libraries

using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
public class PhotoRouteHandler : IRouteHandler
{
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        requestContext.HttpContext.Response.Clear();
        //Cache the photo in the browser to avoid unnecessary requests.
        HttpCachePolicyBase cache = requestContext.HttpContext.Response.Cache;
        TimeSpan cacheDuration = TimeSpan.FromSeconds(86400);
        cache.SetCacheability(HttpCacheability.Public);
        cache.SetExpires(DateTime.Now.Add(cacheDuration));
        cache.SetMaxAge(cacheDuration);
        cache.AppendCacheExtension("must-revalidate, proxy-revalidate");
        //Get the size and url of the photo
        string photoUrl = requestContext.RouteData.Values["photoUrl"].ToString();
        string size = requestContext.RouteData.Values["size"].ToString();
        //Set the content type of the response
        requestContext.HttpContext.Response.ContentType = GetContentType(photoUrl);
        Image img = null;
        Image source;
        bool resizedFile = false;
        //Check if the photo already exists resized on your HDD
        if (File.Exists(Path.Combine(@"C:MySiteContent", "Photos", size, photoUrl)))
        {
            img = Image.FromFile(Path.Combine(@"C:MySiteContent", "Photos", size, photoUrl));
            resizedFile = true;
        }
        else
        {
            try
            {
                //Try to get the photo from the HDD
                source = Image.FromFile(Path.Combine(@"C:MySiteContentPhotos", photoUrl));
            }
            catch
            {
                //If photo doesn't exist on your HDD, send back the default image placeholder
                source = Image.FromFile(Path.Combine(@"C:MySiteContentPhotos", "default.jpg"));
                resizedFile = true; //Used later so we don't store the placeholder
            }
            // Resize the image to completely fit into the size of the rectangle
            if (size == "thumb")
                img = Thumbnailer.FillImage(Thumbnailer.ResizeImage(source, new Size(119, 88)),
                      new Size(119, 88), Thumbnailer.Anchor.Center);
            // Resize and crop the image to completely fill the rectangle
            else if (size == "small")
                img = Thumbnailer.ResizeCrop(source, new Size(284, 205));
            // Resize the image to have a width of 516px
            else if (size == "large")
                img = Thumbnailer.ResizeImage(source,
                      Thumbnailer.GetNewSize(source.Size, new Size(516, 516),
                      Thumbnailer.ResizeMode.FixedWidth));
            // Default rezise for all images where size wasn't accounted for
            else
                img = Thumbnailer.ResizeImage(source,
                      Thumbnailer.GetNewSize(source.Size, new Size(400, 300),
                      Thumbnailer.ResizeMode.FixedWidth));
        }
        if (img != null)
        {
            if (GetContentType(photoUrl) == "image/png")
            {
                MemoryStream memImg = new MemoryStream();
                EncoderParameter qualityParam = new
                EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 1000L);
                ImageCodecInfo pngCodec = Thumbnailer.getEncoderInfo("image/png");
                EncoderParameters encoderParams = new EncoderParameters(1);
                encoderParams.Param[0] = qualityParam;
                if (!resizedFile)
                {
                    //This is the first time this photo has been viewed at this size, so we'll save
                    //it in a folder named after the size, so we don't have to resize it again later
                    if (!Directory.Exists(Path.Combine(@"C:MySiteContentPhotos", size)))
                        Directory.CreateDirectory(Path.Combine(@"C:MySiteContentPhotos", size));
                    img.Save(Path.Combine(@"C:MySiteContent", "Photos", size, photoUrl),
                    pngCodec, encoderParams);
                }
                img.Save(memImg, pngCodec, encoderParams);
                memImg.WriteTo(requestContext.HttpContext.Response.OutputStream);
                img.Dispose();
            }
            else
            {
                MemoryStream memImg = new MemoryStream();
                EncoderParameter qualityParam = new
                EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
                ImageCodecInfo jpegCodec = Thumbnailer.getEncoderInfo("image/jpeg");
                EncoderParameters encoderParams = new EncoderParameters(1);
                encoderParams.Param[0] = qualityParam;
                if (!resizedFile)
                {
                    if (!Directory.Exists(Path.Combine(@"C:MySiteContent", "Photos", size)))
                        Directory.CreateDirectory(Path.Combine(@"C:MySiteContentPhotos", size));
                    img.Save(Path.Combine(@"C:MySiteContent", "Photos", size, photoUrl),
                    jpegCodec, encoderParams);
                }
                img.Save(memImg, jpegCodec, encoderParams);
                memImg.WriteTo(requestContext.HttpContext.Response.OutputStream);
                img.Dispose();
            }
        }
        requestContext.HttpContext.Response.End();
        return null;
    }
    private static string GetContentType(String path)
    {
        switch (Path.GetExtension(path))
        {
            case ".bmp": return "image/bmp";
            case ".gif": return "image/gif";
            case ".jpg": return "image/jpeg";
            case ".png": return "image/png";
            default: break;
        }
        return "";
    }
}

Tags

utils
Alexandru Puiu

Alexandru Puiu

Engineer / Security Architect

Systems Engineering advocate, Software Engineer, Security Architect / Researcher, SQL/NoSQL DBA, and Certified Scrum Master with a passion for Distributed Systems, AI and IoT..

Expertise

.NET
RavenDB
Kubernetes

Social Media

githubtwitterwebsite

Related Posts

RavenDB Integration Testing
Using RavenDB in Integration Testing
December 24, 2022
2 min

Subscribe To My Newsletter

I'll only send worthwhile content I think you'll want, less than once a month, and promise to never spam or sell your information!
© 2023, All Rights Reserved.

Quick Links

Get In TouchAbout Me

Social Media