Feedback

C# - Bilder proportional Skalieren

Veröffentlicht von am 12/11/2009
(3 Bewertungen)
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

 

Logge dich ein, um hier zu kommentieren!