35

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

在这一点上,当我简单地调用 Image.Save() 而不指定压缩质量时,我真的不明白发生了什么。当我将质量设置为 100(基本上没有压缩)时,文件大小如何(在修改图像后)与原始大小如此接近,当我将质量设置为 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

4 回答 4

21

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

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

于 2010-10-18T12:28:57.570 回答
6

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

于 2010-10-18T08:17:16.750 回答
0

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

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

jpg编码步骤

关于大小的变化(没有添加的行),我不确定您重新打开并重新保存了哪个图像

为了进一步调查,我在没有明确设置质量的情况下打开并保存,文件大小完全相同

如果您打开旧(原始正常大小)图像并重新保存它,那么默认压缩和原始图像压缩可能相同。如果您打开新的(大 4 倍)图像并重新保存它,那么保存方法的默认压缩可能来自图像(就像加载时一样)。

同样,我不知道保存方法,所以我只是提出想法(也许他们会给你一个线索)。

于 2010-10-18T09:19:07.923 回答
0

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

这也是为什么如果您打算之后对文件进行任何编辑,您应该始终尝试以无损格式(例如 PNG)保存,否则您将通过多次有损转换影响输出质量。

于 2010-10-18T13:33:38.850 回答