2009-07-21 3 views
2

Ich habe eine einfache PhotoEditor-Hilfsklasse geschrieben, um Bilder, die auf meine Website hochgeladen wurden, zu verkleinern und zu beschneiden. Alles funktioniert, aber ich sehe eine unbefriedigende Qualität, wenn das Bild in der Datei gespeichert wird. Ich habe über die verschiedenen Einstellungen gelesen, die Sie unten optimieren können, ist meine Einstellung für das Ändern der Größe, das Zuschneiden ist identisch.Skalierung der Bildqualitätsreduktion

public Image ResizeImage(Image imgToResize, Size size) 
    { 
     int sourceWidth = imgToResize.Width; 
     int sourceHeight = imgToResize.Height; 

     float nPercentW = (size.Width/(float) sourceWidth); 
     float nPercentH = (size.Height/(float) sourceHeight); 

     float nPercent = nPercentH < nPercentW ? nPercentH : nPercentW; 

     var destWidth = (int) (sourceWidth*nPercent); 
     var destHeight = (int) (sourceHeight*nPercent); 

     var src = imgToResize; 

     using (var dst = new Bitmap(destWidth, destHeight, imgToResize.PixelFormat)) 
     { 
      dst.SetResolution(imgToResize.HorizontalResolution, imgToResize.VerticalResolution); 

      using (var g = Graphics.FromImage(dst)) 
      { 
       var mime = GetMimeType(imgToResize); 
       ImageFormat format; 
       if (mime == "image/gif" || mime == "image/png") 
       { 
        //convert all gif to png, better resize quality 
        g.SmoothingMode = SmoothingMode.AntiAlias; 
        g.InterpolationMode = InterpolationMode.HighQualityBicubic; 
        g.DrawImage(src, 0, 0, dst.Width, dst.Height); 
        format = ImageFormat.Png; 
       } 
       else 
       { 
        //jpeg 
        g.CompositingQuality = CompositingQuality.HighQuality; 
        g.InterpolationMode = InterpolationMode.HighQualityBicubic; 
        g.SmoothingMode = SmoothingMode.HighQuality; 
        g.PixelOffsetMode = PixelOffsetMode.HighQuality; 
        format = ImageFormat.Jpeg; 
       } 
       g.DrawImage(src, 0, 0, dst.Width, dst.Height); 

       // At this point the new bitmap has no MimeType 
       // Need to output to memory stream 
       var m = new MemoryStream(); 
       dst.Save(m, format); 

       var img = Image.FromStream(m); 

       return img; 
      } 
     } 
    } 

Wie man sehen kann ich die vorgeschlagenen Einstellungen für die Interpolation verwenden, Glättung usw. Ich bin auch die JPEG mit Qualität Speicher 100.er

Das resultierende Bild hat spürbar Verwischung und Artefakte, auch wenn die Größenänderung nach unten zu eine bescheidene 75% seiner ursprünglichen Größe. Ich schaute mich um und das ist der empfohlene Weg. Ich fand einen vereinfachten Weg, um die Größe zu ändern und entschied mich, es zu versuchen.

Überraschenderweise erzeugt dies ein viel schöneres Bild, obwohl es ein bisschen größer ist ~ 30% größer im Speicherbedarf.

Meine Frage ist, was ist der Unterschied und welche Einstellung fehlt mir bei meiner Größenänderungsroutine, die für das hässlichere Ergebnis verantwortlich sein könnte. Ich möchte meine Resize-Routine dazu bringen, genau das gleiche Ergebnis wie die einfache Resize zu erzielen.

Ihre Hilfe wird sehr geschätzt. Dies ist mein erster Ausflug in die Bildverarbeitung.

EDIT

Einfache Resize (82KB)

simple http://img189.imageshack.us/img189/2137/simpleresize.jpg

My Resize (55KB)

complex http://img12.imageshack.us/img12/4023/complexresize.jpg

+1

Die dst.Save (m, Format); sieht aus wie dein Problem. Sie kodieren es dort als jpeg, mit Standardqualität (nicht 100%), und dekodieren es dann sofort zu einem Bild zurück. dst ist bereits ein Image (Bitmap-Klasse erbt von Image), sodass Sie es einfach unverändert zurückgeben können. – David

+0

Hallo David. Du hattest Recht. Mein Argument hinter diesem Schritt war, dass der Mimetyp Teil des resultierenden Bildes war. Ich speichere das Bild vorübergehend in der Sitzung und wollte es später abrufen können. Wenn Sie Ihre Antwort aktualisieren, markieren Sie sie als beantwortet. – madcapnmckay

Antwort

2

Mein erster Gedanke war, dass .NET die JPEG-Encoder verwendet Chroma Subsampling auch bei höchster Qualität g, so wird Farbinformation mit halber Auflösung gespeichert. Die Einstellung ist fest codiert, soweit ich das beurteilen kann. Aber das würde nicht erklären, warum Sie im zweiten Beispiel bessere Qualität bekommen würden. Es sei denn, in der 2. Version wurde kein Antialiasing verwendet, was zu einem schärferen Bild (aber geringerer Qualität) führte und die Artefakte blieben unbemerkt.

Edit: Die dst.Save (m, Format); sieht aus wie dein Problem. Sie kodieren es dort als jpeg, mit Standardqualität (nicht 100%), und dekodieren es dann sofort zu einem Bild zurück. dst ist bereits ein Bild (Bitmap-Klasse von Bild erbt), so können Sie es nur zurückkehren, wie sie ist

+0

Danke für eine schnelle Antwort. Ich habe versucht, die AA-Einstellungen zu ändern, um zu sehen, ob es hilft, aber es scheint nicht die Ursache der Artefakte zu sein. Ich flippe zurück und viert zwischen der einfachen Größe und dem Komplex und die Artefakte sind nur auf dem Komplex vorhanden. – madcapnmckay

+0

Wer weiß, wie die Standardqualität ist? – Liam

4

ich dieses Beispiel Code-Snippet gefunden (sorry ich die Quelle vergessen haben), die Ihnen helfen:

// Create parameters 
EncoderParameters params = new EncoderParameters (1); 

// Set quality (100) 
params.Param[0] = new EncoderParameter(Encoder.Quality, 100); 

// Create encoder info 
ImageCodecInfo codec = null; 
foreach (ImageCodecInfo codectemp in ImageCodecInfo.GetImageDecoders()) 
{ 
    if (codectemp.MimeType == "image/jpeg") 
    { 
     codec = codectemp; 
     break; 
    } 
} 

// Check 
if (codec == null) 
    throw new Exception("Codec not found for image/jpeg"); 

// Save 
image.Save(filename, codec, params); 
+0

Schön. Es bewahrt die Qualität des Bildes und reduziert die Bildgröße. – Gabriel