What is the fastest and more reliable way of generating thumbnails in .NET? I need to get any image, compress it in JPEG and resize it.
I've seen several examples with GDI+, some non-free components and I remember WPF has some good stuff about imaging. GDI+ is pretty old and the WPF stuff maybe has no benefits on a server environment though.
This has to work in a ASP.NET MVC application that runs on full trust, and if possible, synchronously.
What would you recommend?
UPDATE:
Based on Mantorok's answer I have worked out this example, but it's still GDI+, and it crashes if I try with a large image:
public void GenerateThumbnail(String filename, Int32? desiredWidth,
Int32? desiredHeight, Int64 quality, Stream s)
{
using (Image image = Image.FromFile(filename))
{
Int32 width=0, height=0;
if ((!desiredHeight.HasValue && !desiredWidth.HasValue) ||
(desiredHeight.HasValue && desiredWidth.HasValue))
throw new ArgumentException(
"You have to specify a desired width OR a desired height");
if (desiredHeight.HasValue)
{
width = (desiredHeight.Value * image.Width) / image.Height;
height = desiredHeight.Value;
}
else
{
height = (desiredWidth.Value * image.Height) / image.Width;
width = desiredWidth.Value;
}
using (var newImage = new Bitmap(width, height))
using (var graphics = Graphics.FromImage(newImage))
using (EncoderParameter qualityParam =
new EncoderParameter(System.Drawing.Imaging.Encoder.Quality,
quality))
using (EncoderParameters encoderParams = new EncoderParameters(1))
{
graphics.DrawImage(image, 0, 0, width, height);
ImageCodecInfo jpegCodec = ImageCodecInfo.GetImageEncoders().
Single(e => e.MimeType.Equals("image/jpeg",
StringComparison.Ordinal));
encoderParams.Param[0] = qualityParam;
newImage.Save(s, jpegCodec, encoderParams);
}
}
}
This has done me fine for years:
public static void CreateThumbnail(string filename, int desiredWidth, int desiredHeight, string outFilename)
{
using (System.Drawing.Image img = System.Drawing.Image.FromFile(filename))
{
float widthRatio = (float)img.Width / (float)desiredWidth;
float heightRatio = (float)img.Height / (float)desiredHeight;
// Resize to the greatest ratio
float ratio = heightRatio > widthRatio ? heightRatio : widthRatio;
int newWidth = Convert.ToInt32(Math.Floor((float)img.Width / ratio));
int newHeight = Convert.ToInt32(Math.Floor((float)img.Height / ratio));
using (System.Drawing.Image thumb = img.GetThumbnailImage(newWidth, newHeight, new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailImageAbortCallback), IntPtr.Zero))
{
thumb.Save(outFilename, System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
}
public static bool ThumbnailImageAbortCallback()
{
return true;
}