views:

2159

answers:

8

Story: The user uploads an image that will be added to a photo gallery. As part of the upload process, we need to A) store the image on the web server's hard drive and B) store a thumbnail of the image on the web server's hard drive.

"Best" here is defined as

  • Relatively easy to implement, understand, and maintain
  • Results in a thumbnail of reasonable quality

Performance and high-quality thumbnails are secondary.

+12  A: 

I suppose your best solution would be using the GetThumbnailImage from the .NET Image class.

// Example in C#, should be quite alike in ASP.NET
// Assuming filename as the uploaded file
using ( Image bigImage = new Bitmap( filename ) )
{
   // Algorithm simplified for purpose of example.
   int height = bigImage.Height / 10;
   int width = bigImage.Width / 10;

   // Now create a thumbnail
   using ( Image smallImage = image.GetThumbnailImage( width, 
                                                       height,
                                                       new Image.GetThumbnailImageAbort(Abort), IntPtr.Zero) )
   {
      smallImage.Save("thumbnail.jpg", ImageFormat.Jpeg);
   }
}
Huppie
+3  A: 
chrissie1
"Sorry the code tag doesn't like vb.net code." => I don't blame it :P
AlexanderN
A: 

You can use the Image.GetThumbnailImage function to do it for you.

http://msdn.microsoft.com/en-us/library/system.drawing.image.getthumbnailimage.aspx (.NET 3.5)

http://msdn.microsoft.com/en-us/library/system.drawing.image.getthumbnailimage(VS.80).aspx (.NET 2.0)

public bool ThumbnailCallback()
{
  return false;
}

public void Example_GetThumb(PaintEventArgs e)
{
  Image.GetThumbnailImageAbort myCallback = new Image.GetThumbnailImageAbort(ThumbnailCallback);
  Bitmap myBitmap = new Bitmap("Climber.jpg");
  Image myThumbnail = myBitmap.GetThumbnailImage(40, 40, myCallback, IntPtr.Zero);
  e.Graphics.DrawImage(myThumbnail, 150, 75);
}
Mark Ingram
A: 

I tend to recommend this solution by Rick Strahl. I haven't tested it myself but it's coming from a MVP so it may be worth to try.

I saw this server-side image resizing module for ASP.NET made by Nathanael Jones. But it's 69$ to get the source. So it may be a no-go on this one.

Pascal Paradis
+20  A: 

GetThumbnailImage would work, but if you want a little better quality you can specify your image options for the BitMap class and save your loaded image into there. Here is some sample code:

Image photo; // your uploaded image

Bitmap bmp = new Bitmap(resizeToWidth, resizeToHeight);
graphic = Graphics.FromImage(bmp);
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.CompositingQuality = CompositingQuality.HighQuality;
graphic.DrawImage(photo, 0, 0, resizeToWidth, resizeToHeight);
imageToSave = bmp;

This provides better quality than GetImageThumbnail would out of the box

Sean Chambers
this is exactly what I was looking for! Thanks for sharing.
sean717
A: 

New feature: ASP.NET Generated Image

kokos
+1  A: 

Avoid GetThumbnailImage - it will provide very unpredictable results, since it tries to use the embedded JPEG thumbnail if available - even if the embedded thumbnail is entirely the wrong size. DrawImage() is a much better solution.

Wrap your bitmap in a using{} clause - you don't want leaked handles floating around...

Also, you'll want to set your Jpeg encoding quality to 90, which is where GDI+ seems to shine the best:

System.Drawing.Imaging.ImageCodecInfo[] info = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders();
System.Drawing.Imaging.EncoderParameters encoderParameters;
encoderParameters = new System.Drawing.Imaging.EncoderParameters(1);
encoderParameters.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 90L);

thumb.Save(ms, info[1], encoderParameters);

I know that a large percentage of my customers buy my image resizing code to use for integration with image upload systems. Due to the good documentation, very few need help modifying the code. For those who do, I offer customization for a small fee.

+5  A: 

Using an example above and some from a couple of other places, here is an easy function to just drop in (thanks to Nathanael Jones and others here).

using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;

public static void ResizeImage(string FileNameInput, string FileNameOutput, double ResizeHeight, double ResizeWidth, ImageFormat OutputFormat)
{
    using (System.Drawing.Image photo = new Bitmap(FileNameInput))
    {
        double aspectRatio = (double)photo.Width / photo.Height;
        double boxRatio = ResizeWidth / ResizeHeight;
        double scaleFactor = 0;

        if (photo.Width < ResizeWidth && photo.Height < ResizeHeight)
        {
            // keep the image the same size since it is already smaller than our max width/height
            scaleFactor = 1.0;
        }
        else
        {
            if (boxRatio > aspectRatio)
                scaleFactor = ResizeHeight / photo.Height;
            else
                scaleFactor = ResizeWidth / photo.Width;
        }

        int newWidth = (int)(photo.Width * scaleFactor);
        int newHeight = (int)(photo.Height * scaleFactor);

        using (Bitmap bmp = new Bitmap(newWidth, newHeight))
        {
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.SmoothingMode = SmoothingMode.HighQuality;
                g.CompositingQuality = CompositingQuality.HighQuality;
                g.PixelOffsetMode = PixelOffsetMode.HighQuality;

                g.DrawImage(photo, 0, 0, newWidth, newHeight);

                if (ImageFormat.Png.Equals(OutputFormat))
                {
                    bmp.Save(FileNameOutput, OutputFormat);
                }
                else if (ImageFormat.Jpeg.Equals(OutputFormat))
                {
                    ImageCodecInfo[] info = ImageCodecInfo.GetImageEncoders();
                    EncoderParameters encoderParameters;
                    using (encoderParameters = new System.Drawing.Imaging.EncoderParameters(1))
                    {
                        // use jpeg info[1] and set quality to 90
                        encoderParameters.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 90L);
                        bmp.Save(FileNameOutput, info[1], encoderParameters);
                    }
                }
            }
        }
    }
}
also a great example of setting quality options
TheSoftwareJedi