I need to resize a lot of images without losing to much quality.
Using PresentationFramework (WPF) is pretty fast, but quality is poor.
Using GDI+, it's good quality, but locked to UI-Thread -> singleCored. :-(
Is there a good and fast algorithm combining speed and quality in one piece of code? ;-)
GDI+ (a.k.a. System.Drawing
) doesn't need the message pump and will happily work on multiple threads; only real controls do - you can even use Bitmap
in a console application (which doesn't have a message pump).
Thus, for instance, you could do the following (I have tested this):
static void Main(string[] args)
{
foreach (var file in Directory.GetFiles("C:\\MyImages", "*.jpg"))
{
// Spawn threads.
new Action<string, float>(ResizeImage).BeginInvoke(file, 0.1f, null, null);
}
Console.ReadLine();
}
public static void ResizeImage(string filename, float scale)
{
using (var bitmap = Image.FromFile(filename))
using (var resized = ResizeBitmap(bitmap, 0.1f, InterpolationMode.HighQualityBicubic))
{
var newFile = Path.ChangeExtension(filename, ".thumbnail" + Path.GetExtension(filename));
if (File.Exists(newFile))
File.Delete(newFile);
resized.Save(newFile);
}
}
public static Bitmap ResizeBitmap(Image source, float scale, InterpolationMode quality)
{
if (source == null)
throw new ArgumentNullException("source");
// Figure out the new size.
var width = (int)(source.Width * scale);
var height = (int)(source.Height * scale);
// Create the new bitmap.
// Note that Bitmap has a resize constructor, but you can't control the quality.
var bmp = new Bitmap(width, height);
using (var g = Graphics.FromImage(bmp))
{
g.InterpolationMode = quality;
g.DrawImage(source, new Rectangle(0, 0, width, height));
g.Save();
}
return bmp;
}
Edit: According to this post it seems as though System.Drawing has a global lock; especially with DrawImage()
(although keep in mind, this is not because of the message pump). Unfortunately the only way to get multithreaded access would probably be to use DirectX/SharpDX and create the device with multithreading enabled; create some backbuffers and do the resizing there - you can then tweak the minification/maxification filters. I am not sure if you can Draw()
from multiple threads in DirectX - but even if you can't you should be able to get way more throughput from it (even on a single thread).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With