Frage

Ich bin Ändern der Größe einige Bilder auf die Bildschirmauflösung des Benutzers; wenn das Seitenverhältnis nicht stimmt, sollte das Bild geschnitten werden. Mein Code sieht wie folgt aus:

protected void ConvertToBitmap(string filename)
    {
        var origImg = System.Drawing.Image.FromFile(filename);
        var widthDivisor = (double)origImg.Width / (double)System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width;
        var heightDivisor = (double)origImg.Height / (double)System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;
        int newWidth, newHeight;

        if (widthDivisor < heightDivisor)
        {
            newWidth = (int)((double)origImg.Width / widthDivisor);
            newHeight = (int)((double)origImg.Height / widthDivisor);
        }
        else
        {
            newWidth = (int)((double)origImg.Width / heightDivisor);
            newHeight = (int)((double)origImg.Height / heightDivisor);
        }

         var newImg = origImg.GetThumbnailImage(newWidth, newHeight, null, IntPtr.Zero);
        newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);
    }

In den meisten Fällen funktioniert das gut. Aber für einige Bilder, hat das Ergebnis eine extrem schlechte Qualität. Es sieht aus wie das zu etwas sehr klein (Miniaturgröße) und vergrößert wieder verkleinert worden wäre .. Aber die Auflösung des Bildes korrekt ist. Was kann ich tun?

Beispiel orig Bild: alt text http://img523.imageshack.us/img523/1430/naturaerowoods.jpg

Beispiel skalierte Bild: alt text

Hinweis: Ich habe eine Anwendung WPF aber ich benutze die WinForms-Funktion zum Ändern der Größe, weil es einfacher ist, und weil ich schon einen Verweis auf System.Windows.Forms für einen Tray-Icon benötigen

.
War es hilfreich?

Lösung

Ändern Sie die letzten beiden Zeilen Ihrer Methode, um diese:

var newImg = new Bitmap(newWidth, newHeight);
Graphics g = Graphics.FromImage(newImg);
g.DrawImage(origImg, new Rectangle(0,0,newWidth,newHeight));
newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);
g.Dispose();

Andere Tipps

Ich kann zur Zeit nicht in die .NET-Quelle spähe, aber wahrscheinlich ist das Problem in der Image.GetThumbnailImage Methode. Auch sagt MSDN, dass „es funktioniert gut, wenn das angeforderte Thumbnail-Bild mit einer Größe von ca. 120 x 120 Pixel hat, aber es fordern Sie ein großes Miniaturbild (zB 300 x 300) aus einem Bild, das eine eingebettete Miniaturbild hat, könnte es sein ein merklicher Qualitätsverlust in der Miniaturansicht“. Für wahre Größe neu bestimmen (das heißt nicht thumbnailing), sollten Sie die Graphics.DrawImage Methode verwenden. Sie können auch mit dem Graphics.InterpolationMode müssen spielen eine bessere Qualität zu bekommen, wenn nötig.

Wenn Sie eine Miniaturansicht erstellen, wahrscheinlich eine Methode namens GetThumbnailImage verwendet, ist keine gute Idee ...

Für weitere Optionen, haben einen Blick auf diesem Artikel Codeproject . Insbesondere schafft es ein neues Bild, schafft eine Graphics für sie und setzt den Interpolationsmodus HighQualityBicubic und zieht das Originalbild auf die Grafik. Ein Versuch wert, mindestens.

Wie bereits erwähnt auf MSDN , GetThumbnailImage() ist nicht zu tun beliebige Skalierung ausgelegt. Alles, was über 120x120 sollte manuell skaliert werden. Versuchen Sie stattdessen:

using(var newImg = new Bitmap(origImg, newWidth, newHeight))
{
    newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);
}

Bearbeiten

Als Ausgangspunkt der Klärung dieser Überlastung des Bitmap Konstruktor ruft Graphics.DrawImage, obwohl Sie haben keine Kontrolle über die Interpolation.

anstelle diesem Code:

newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);

verwenden diese:

System.Drawing.Imaging.ImageCodecInfo[] info = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders();
System.Drawing.Imaging.EncoderParameters param = new System.Drawing.Imaging.EncoderParameters(1);
param.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
newImg.Save(dest_img, info[1], param);

Für Beispiele ist das Originalbild JPG und das geänderte Bild ist PNG. Konvertieren Sie zwischen den Formaten absichtlich? Der Wechsel zwischen verschiedenen verlustbehafteten Kompressionsschemata kann Qualitätsverlust führen.

Sie erhöhen oder die Größe des Bildes zu verringern, wenn Sie die Größe ändern? Wenn Sie ein größeres Bild von einem kleineren zu schaffen, diese Art von Verschlechterung zu erwarten ist.

Die Bilder werden auf jeden Fall verschlechtert werden, wenn man sie vergrößern.

setzen Einige Kamera eine Größe veränderte Thumbnail in der Datei selbst vermutlich für Vorschauzwecke auf dem Gerät selbst.

Die GetThumbnail Methode tatsächlich bekommt dieses Thumbnail Bild, das in der Bilddatei eingebettet ist, anstatt die höher res Methode des Erhaltens.

Die einfache Lösung ist .Net in Wegwerfen dass Thumbnail Informationen, bevor Sie Ihre Größe ändern oder eine andere Operation zu betrügen. wie so ....

img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX); 
//removes thumbnails from digital camera shots
img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX);

Wenn Sie beschränke Proportionen, um die Größe versuchen ich eine Erweiterungsmethode auf System.Drawing.Image schrieb, dass Sie praktisch finden könnte.

/// <summary>
/// 
/// </summary>
/// <param name="img"></param>
/// <param name="size">Size of the constraining proportion</param>
/// <param name="constrainOnWidth"></param>
/// <returns></returns>
public static System.Drawing.Image ResizeConstrainProportions(this System.Drawing.Image img,
    int size, bool constrainOnWidth, bool dontResizeIfSmaller)
{
    if (dontResizeIfSmaller && (img.Width < size))
        return img;
    img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX); 
    img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX);
    float ratio = 0;
    ratio = (float)img.Width / (float)img.Height;

    int height, width = 0;
    if (constrainOnWidth)
    {
        height = (int)(size / ratio);
        width = size;
    }
    else
    {
        width = (int)(size * ratio);
        height = size;
    }
    return img.GetThumbnailImage(width, height, null, (new System.IntPtr(0)));
}

Das wird weit variieren, basierend auf den folgenden Faktoren ab:

  1. Wie genau die Zielauflösung entspricht einen „natürlichen“ Maßstab der ursprünglichen Auflösung
  2. Die Quellbild-Farbtiefe
  3. Die Bildtyp (en) - einige weitere verlustbehaftete als andere
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top