webentwicklung-frage-antwort-db.com.de

Welche Qualitätsstufe verwendet Image.Save () für JPEG-Dateien?

Ich habe gerade eine echte Überraschung erlebt, als ich eine JPG-Datei geladen und herumgedreht habe und sie mit einer Qualität von 100 gespeichert habe. Die Größe war fast viermal so groß wie das Original. Zur weiteren Untersuchung öffne und speichere ich ohne explizite Einstellung die Qualität und die Dateigröße genau gleich. Ich dachte, das lag daran, dass sich nichts geändert hat, also werden genau die gleichen Bits in eine Datei zurückgeschrieben. Um diese Annahme zu testen, habe ich diagonal eine dicke fette Linie über das Bild gezogen und erneut gespeichert, ohne die Qualität einzustellen (diesmal hatte ich erwartet, dass die Datei hochspringt, weil sie "schmutzig" wäre), aber sie hat ~ 10 KB abgenommen!

An diesem Punkt verstehe ich wirklich nicht, was passiert, wenn ich einfach Image.Save () aufrufe, ohne eine Komprimierungsqualität anzugeben. Wie ist die Dateigröße (nachdem das Bild geändert wurde) so nahe an der Originalgröße, wenn noch keine Qualität eingestellt ist? Wenn ich die Qualität auf 100 (im Grunde keine Komprimierung) stelle, ist die Dateigröße um ein Vielfaches größer als das Original.

Ich habe die Dokumentation zu Image.Save () gelesen und es fehlen Details darüber, was sich hinter den Kulissen abspielt. Ich habe auf jede erdenkliche Weise gegoogelt, aber ich kann keine zusätzlichen Informationen finden, die erklären, was ich sehe. Ich arbeite seit 31 Stunden ohne Unterbrechung, also vermisse ich vielleicht etwas Offensichtliches; 0)

All dies ist geschehen, während ich einige Bibliotheksmethoden implementiere, um Bilder in einer Datenbank zu speichern. Ich habe unsere "SaveImage" -Methode überladen, um das explizite Einstellen einer Qualität zu ermöglichen, und während meines Tests bin ich auf die merkwürdigen (für mich) Ergebnisse gestoßen, die oben erläutert wurden. Jedes Licht, das Sie ausstrahlen können, wird geschätzt.

Hier ist ein Code, der veranschaulicht, was ich erlebe:

string filename = @"C:\temp\image testing\hh.jpg";
string destPath = @"C:\temp\image testing\";

using(Image image = Image.FromFile(filename))
{
    ImageCodecInfo codecInfo = ImageUtils.GetEncoderInfo(ImageFormat.Jpeg);

    //  Set the quality
    EncoderParameters parameters = new EncoderParameters(1);

    // Quality: 10
    parameters.Param[0] = new EncoderParameter(
        System.Drawing.Imaging.Encoder.Quality, 10L);
    image.Save(destPath + "10.jpg", codecInfo, parameters);

    // Quality: 75
    parameters.Param[0] = new EncoderParameter(
        System.Drawing.Imaging.Encoder.Quality, 75L);
    image.Save(destPath + "75.jpg", codecInfo, parameters);

    // Quality: 100
    parameters.Param[0] = new EncoderParameter(
        System.Drawing.Imaging.Encoder.Quality, 100L);
    image.Save(destPath + "100.jpg", codecInfo, parameters);

    //  default
    image.Save(destPath + "default.jpg", ImageFormat.Jpeg);

    //  Big line across image
    using (Graphics g = Graphics.FromImage(image))
    {
        using(Pen pen = new Pen(Color.Red, 50F))
        {
            g.DrawLine(pen, 0, 0, image.Width, image.Height);
        }
    }

    image.Save(destPath + "big red line.jpg", ImageFormat.Jpeg);
}

public static ImageCodecInfo GetEncoderInfo(ImageFormat format)
{
    return ImageCodecInfo.GetImageEncoders().ToList().Find(delegate(ImageCodecInfo codec)
    {
        return codec.FormatID == format.Guid;
    });
}
33
Steve K

Bei Verwendung von Reflektor stellt sich heraus, dass Image.Save() auf die GDI + -Funktion GdipSaveImageToFile mit der encoderParams NULL-Funktion zurückgeht. Ich denke, die Frage ist, was der JPEG-Encoder macht, wenn er eine Null encoderParams bekommt. 75% wurden hier vorgeschlagen, aber ich kann keine soliden Referenzen finden.

EDITSie könnten es wahrscheinlich selbst herausfinden, indem Sie Ihr Programm oben für Qualitätswerte von 1..100 ausführen und sie mit dem mit der Standardqualität gespeicherten jpg vergleichen (z. B. fc.exe/B) )

19
Ohad Schneider

IIRC ist 75%, aber ich kann mich nicht erinnern, wo ich das gelesen habe.

5
leppie

Ich weiß nicht viel über die Image.Save-Methode, aber ich kann Ihnen sagen, dass das Hinzufügen einer dicken Linie die Größe des JPG-Bildes logisch reduzieren würde. Dies liegt an der Art und Weise, wie ein JPG gespeichert (und verschlüsselt) wird.

Die dicke schwarze Linie sorgt für eine sehr einfache und kleinere Codierung (wenn ich mich recht erinnere, ist dies vor allem nach der diskreten Cosinus-Transformation relevant), sodass das modifizierte Bild mit weniger Daten (Bytes) gespeichert werden kann.

jpg-Codierschritte

Bei den Größenänderungen (ohne die hinzugefügte Zeile) bin ich nicht sicher, welches Bild Sie erneut geöffnet und gespeichert haben 

Zur weiteren Untersuchung habe ich geöffnet und gespeichert, ohne explizit die Qualität und die Dateigröße einzustellen

Wenn Sie das alte Bild (Original-Normalgröße) geöffnet und erneut gespeichert haben, sind möglicherweise die Standardkomprimierung und die Original-Bildkomprimierung gleich. Wenn Sie das neue (4X größere) Bild geöffnet und erneut gespeichert haben, dann möglicherweise Die Standardkomprimierung für die Speichermethode wird vom Bild abgeleitet (wie beim Laden).

Ich kenne die Speichermethode auch nicht, also werfe ich nur Ideen aus (vielleicht geben sie Ihnen einen Hinweis).

0
Neowizard

Wenn Sie ein Bild als JPEG-Datei mit einer Qualitätsstufe von <100% speichern, führen Sie Artefakte in das gespeicherte Bild ein, die einen Nebeneffekt des Komprimierungsvorgangs darstellen. Durch das erneute Speichern des Bildes bei 100% wird die Größe Ihrer Datei also tatsächlich über das Original hinaus vergrößert. Ironischerweise befinden sich in der Bitmap weitere Informationen.

Deswegen sollten Sie immer versuchen, in einem verlustfreien Format (z. B. PNG) zu speichern, wenn Sie danach Änderungen an Ihrer Datei vornehmen möchten. Andernfalls beeinträchtigen Sie die Qualität der Ausgabe durch mehrere verlustbehaftete Transformationen.

0
Dave R.