65.9K
CodeProject is changing. Read more.
Home

ASP.NET MVC ImageHandler for Thumbnails

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (2 votes)

Oct 7, 2009

CPOL
viewsIcon

28731

Handling all your images through a custom ActionResult/Controller.

Introduction

As some of you might know, I am a really big fan of community-driven technologies. I also like to contribute myself in order to exchange new ideas and meet new people with common interests. Since I am quite new to ASP.NET MVC, I was thinking I would submit my first contribution: handling all your images through a custom ActionResult/Controller. This allows me to do several things:

  • uniform access to images
  • possibility for custom types (this example always renders as PNG)
  • generation of thumbnails.

The Code

Let's start with the code for the ActionResult (initially inspired by/copy-pasted from this, but since the new RC, it is my own code):

using System.IO;
using System.Web.Mvc;
using System.Drawing;
using System.Drawing.Imaging;

namespace Be.Corebvba.MVC
{
  public class ImageResult : FileStreamResult 
  { 
    public ImageResult(Image input):this(input,input.Width,input.Height) { } 
    public ImageResult(Image input, int width,int height) : 
       base(
         GetMemoryStream(input,width,height,ImageFormat.Png),
         "image/png") 
   { } 

    static MemoryStream GetMemoryStream(Image input,int width, 
                        int height,ImageFormat fmt) 
    { 
       // maintain aspect ratio 
       if (input.Width > input.Height) 
          height = input.Height * width / input.Width; 
       else 
          width = input.Width * height / input.Height; 
       
       var bmp = new Bitmap(input, width, height); 
       var ms = new MemoryStream();
       bmp.Save(ms, ImageFormat.Png); 
       ms.Position = 0; 
       return ms; 
     } 
   } 
}

The code for the controller is pretty straightforward as well:

public ActionResult ThumbImage(int id,int width,int height)
{
   var d = _rDocument.GetById(id);
   Image i=null;
   try
   {
      i = Image.FromFile(d.PhysicalFilename);
      return new Be.Corebvba.MVC.ImageResult(i, width, height);
   }
   catch (Exception ex)
   {
      i = new Bitmap(1, 1);
      return new Be.Corebvba.MVC.ImageResult(i,1,1);
   }
   finally
   {
      if (i != null) i.Dispose();
   }
}

This does need some better error handling, but I suppose you get the idea... (The _rDocument is a pointer to a Document repository which stores physical files.) If you access your images from a database, you could simply use Image.FromStream instead of an Image.FromFile. In my document, I reference the image as follows, et voila, automatic thumbnails:

<% var imgurl = Url.Action("ThumbImage", "Documents", 
                new { id = d.ID,width=100,height=100 }); %>
<img src="<%=imgurl %>" style="float:left"/>