Bertrand Le Roy hat in einem Blogartikel (http://bit.ly/6o4ziC) gezeigt, dass die Bildmanipulationen mit WPF bis zu 3x schneller arbeiten als die Funktionen aus dem Namensraum System.Drawing (GDI+). Auch die Dateigrößen sind geringer bei gleicher oder sogar besserer Bildqualität.
Der hier gezeigten Methode übergibt man zum einen den Stream mit dem Bild (bsp. aus den POST-Daten einer ASP.NET Anwendung), die gewünschte Maximalgröße (Breite und Höhe in Pixeln bei 92 DPI) und den zu verwendenden Algorithmus für die Neuberechnung. Hier empfiehlt sich eigentlich immer "
BitmapScalingMode.HighQuality" bzw. "
BitmapScalingMode.Fant" (beide gleichwertig, ersteres existiert noch aus Kompatibilitätsgründen).
Als Ergebnis bekommt man wieder einen Stream zurück, den man beispielsweise als Datei speichern kann.
Beispiel für ASP.NET MVC:
HttpPostedFileBase posted = Request.Files[file];
string fn = Guid.NewGuid() + ".png";
FileStream fs = System.IO.File.Create("~/upload/" + fn);
Resize(posted.InputStream, 100, 100, BitmapScalingMode.Fant).WriteTo(fs);
fs.Close();
posted.InputStream.Close();
using System;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
public static class ImgScale {
/// <summary>
/// Resizes the specified image stream
/// </summary>
/// <param name="imageStream">The source image stream</param>
/// <param name="maxWidth">maximum width of the scaled image</param>
/// <param name="maxHeight">maximum height of the scaled image</param>
/// <param name="scalingMode">rendering mode</param>
/// <returns></returns>
public static Stream Resize(Stream imageStream, int maxWidth, int maxHeight, BitmapScalingMode scalingMode) {
// Lade den ersten (und meistens einzigen) Frame aus dem Stream der Bilddatei und gib den Algorithmus zum Neuberechnen vor
BitmapDecoder imgDecoder = BitmapDecoder.Create(imageStream, BitmapCreateOptions.None, BitmapCacheOption.Default);
BitmapFrame img = imgDecoder.Frames[0];
DrawingGroup group = new DrawingGroup();
RenderOptions.SetBitmapScalingMode(group, scalingMode);
// Berechne die Verhältnisse des Originalbildes zur gewünschten Maximalgröße und bestimme so welche der beiden übergebenen
// Werte übernommen, und welcher skaliert werden muss
float xP = maxWidth / (float)img.Width;
float yP = maxHeight / (float)img.Height;
if (xP > yP)
maxWidth = Convert.ToInt32(img.Width * yP);
else
maxHeight = Convert.ToInt32(img.Height * xP);
// Lege eine neue Grafik mit den berechneten Maßen an und berechne das Originalbild neu
group.Children.Add(new ImageDrawing(img, new Rect(0, 0, maxWidth, maxHeight)));
DrawingVisual targetVisual = new DrawingVisual();
DrawingContext targetContext = targetVisual.RenderOpen();
targetContext.DrawDrawing(group);
RenderTargetBitmap target = new RenderTargetBitmap(maxWidth, maxHeight, 96, 96, PixelFormats.Default); // 96 DPI, Standart-Bildschirmauflösung
targetContext.Close();
target.Render(targetVisual);
BitmapFrame targetFrame = BitmapFrame.Create(target);
// Der PNG-Encode bietet sich in den meisten Fällen an, da er die beste Qualität bietet
// GIF hat gerade bei Fotos eine zu niedrige Farbanzahl und JPEG hat eine verlustbehaftete Bildkompression
PngBitmapEncoder targetEncoder = new PngBitmapEncoder();
targetEncoder.Frames.Add(targetFrame);
Stream output = null;
targetEncoder.Save(output);
return output;
}
}
Kommentare zum Snippet