What is the “best” way to create a thumbnail using ASP.NET?

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.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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

Method 2

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);
   }
}

Method 3

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);
                    }
                }
            }
        }
    }
}

Method 4

Here is an extension method in VB.NET for the Image Class

Imports System.Runtime.CompilerServices

Namespace Extensions
   ''' <summary>
   ''' Extensions for the Image class.
   ''' </summary>
   ''' <remarks>Several usefull extensions for the image class.</remarks>
   Public Module ImageExtensions

      ''' <summary>
      ''' Extends the image class so that it is easier to get a thumbnail from an image
      ''' </summary>
      ''' <param name="Input">Th image that is inputted, not really a parameter</param>
      ''' <param name="MaximumSize">The maximumsize the thumbnail must be if keepaspectratio is set to true then the highest number of width or height is used and the other is calculated accordingly. </param>
      ''' <param name="KeepAspectRatio">If set false width and height will be the same else the highest number of width or height is used and the other is calculated accordingly.</param>
      ''' <returns>A thumbnail as image.</returns>
      ''' <remarks>
      ''' <example>Can be used as such. 
      ''' <code>
      ''' Dim _NewImage as Image 
      ''' Dim _Graphics As Graphics
      ''' _Image = New Bitmap(100, 100)
      ''' _Graphics = Graphics.FromImage(_Image)
      ''' _Graphics.FillRectangle(Brushes.Blue, New Rectangle(0, 0, 100, 100))
      ''' _Graphics.DrawLine(Pens.Black, 10, 0, 10, 100)
      ''' Assert.IsNotNull(_Image)
      ''' _NewImage = _Image.ToThumbnail(10)
      ''' </code>
      ''' </example>
      ''' </remarks>
      <Extension()> _
      Public Function ToThumbnail(ByVal Input As Image, ByVal MaximumSize As Integer, Optional ByVal KeepAspectRatio As Boolean = True) As Image
         Dim ReturnImage As Image
         Dim _Callback As Image.GetThumbnailImageAbort = Nothing
         Dim _OriginalHeight As Double
         Dim _OriginalWidth As Double
         Dim _NewHeight As Double
         Dim _NewWidth As Double
         Dim _NormalImage As Image
         Dim _Graphics As Graphics

         _NormalImage = New Bitmap(Input.Width, Input.Height)
         _Graphics = Graphics.FromImage(_NormalImage)
         _Graphics.DrawImage(Input, 0, 0, Input.Width, Input.Height)
         _OriginalHeight = _NormalImage.Height
         _OriginalWidth = _NormalImage.Width
         If KeepAspectRatio = True Then
            If _OriginalHeight > _OriginalWidth Then
               If _OriginalHeight > MaximumSize Then
                  _NewHeight = MaximumSize
                  _NewWidth = _OriginalWidth / _OriginalHeight * MaximumSize
               Else
                  _NewHeight = _OriginalHeight
                  _NewWidth = _OriginalWidth
               End If
            Else
               If _OriginalWidth > MaximumSize Then
                  _NewWidth = MaximumSize
                  _NewHeight = _OriginalHeight / _OriginalWidth * MaximumSize
               Else
                  _NewHeight = _OriginalHeight
                  _NewWidth = _OriginalWidth
               End If
            End If
         Else
            _NewHeight = MaximumSize
            _NewWidth = MaximumSize
         End If
         ReturnImage = _
            _NormalImage.GetThumbnailImage(Convert.ToInt32(_NewWidth), Convert.ToInt32(_NewHeight), _Callback, _
                                    IntPtr.Zero)
         _NormalImage.Dispose()
         _NormalImage = Nothing
         _Graphics.Dispose()
         _Graphics = Nothing
         _Callback = Nothing
         Return ReturnImage
      End Function
   End Module
End Namespace

Sorry the code tag doesn’t like vb.net code.

Method 5

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);
}

Method 6

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);


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x