Image.Save()用于jpeg文件的质量等级是多少?

时间:2010-10-18 08:15:36

标签: c# gdi+ system.drawing.imaging

当我加载一个jpg文件然后转过来并以100的质量保存它并且大小几乎是原始文件的4倍时,我真的很惊讶。为了进一步研究我打开并保存而没有明确设置质量和文件大小完全相同。我认为这是因为没有改变所以它只是将完全相同的位写回文件。为了测试这个假设,我在图像上对角线画了一条很大的粗线并再次保存而没有设置质量(这次我希望文件跳起来因为它会“脏”)但它减少了~10Kb!

此时我真的不明白当我简单地调用Image.Save()时指出压缩质量时发生了什么。当我将质量设置为100(基本上没有压缩)时,如果文件大小比原始文件大几倍,文件大小如何接近(在图像修改后)到原始大小时还没有设置质量?

我已经阅读了有关Image.Save()的文档,而且它缺乏关于幕后发生的事情的任何细节。我用谷歌搜索了我能想到的每一种方式,但我找不到任何可以解释我所看到的信息的其他信息。我已经连续工作了31个小时,所以也许我错过了一些明显的东西; 0)

当我实现一些库方法来将图像保存到数据库时,所有这一切都发生了。我已经重载了我们的“SaveImage”方法以允许明确地设置质量,并且在我的测试期间,我遇到了上面解释的奇怪(对我而言)的结果。任何你能摆脱的光都会受到赞赏。

以下是一些代码,用于说明我遇到的问题:

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;
    });
}

4 个答案:

答案 0 :(得分:19)

使用反射器,结果Image.Save()归结为GDI +函​​数GdipSaveImageToFileencoderParams为NULL。所以我认为问题是JPEG编码器在获得空encoderParams时会做什么。这里建议75%,但我找不到任何可靠的参考。

编辑您可以通过运行上面的程序获得质量值1..100并将它们与使用默认质量保存的jpg进行比较(例如,使用fc.exe) / B)

答案 1 :(得分:5)

IIRC,它是75%,但我不记得我在哪里读到这个。

答案 2 :(得分:0)

我对Image.Save方法了解不多,但我可以告诉你,添加胖线会逻辑上减小jpg图像的大小。这是由于jpg的保存(和编码)方式。

粗黑线表示非常简单和较小的编码(如果我没记错的话,这主要是在离散余弦变换后相关的),因此可以使用较少的数据(字节)存储修改后的图像。

jpg encoding steps

关于尺寸的变化(没有添加的行),我不确定您重新打开和重新保存的图像

  

进一步调查我打开并保存而没有明确设置质量和文件大小完全相同

如果您打开旧的(原始正常尺寸)图像并重新保存,则默认压缩和原始图像压缩可能相同。 如果您打开了新的(大4倍)图像并重新保存它,那么保存方法的默认压缩可能是从图像中导出的(就像加载时一样)。

同样,我不知道保存方法,所以我只是抛出想法(也许他们会给你带头)。

答案 3 :(得分:0)

当您将图像保存为质量级别<100%的JPEG文件时,您会将假象引入已保存的图像,这是压缩过程的副作用。这就是为什么将图像重新保存为100%实际上会使文件的大小超出原始范围 - 具有讽刺意味的是,位图中存在更多信息。

这也是为什么你应该总是尝试以非损耗格式(如PNG)保存,如果你打算以后对你的文件进行任何编辑,否则你将通过多个有损影响输出的质量变换。