【问题标题】:Why Bitmap.Save changes image's size?为什么 Bitmap.Save 会改变图像的大小?
【发布时间】:2015-08-31 18:11:51
【问题描述】:

我成功更改了图像的DateTaken 属性。但是,在重新保存图像后,它的大小发生了变化。我检查了Matlab,两个图像的字节是相同的。

为了检查更改属性是否会更改大小,我决定只打开文件并保存它而不更改任何属性。代码如下:

using (var image = new Bitmap(@"C:\Temp\1.jpg"))
{  
    image.Save(@"C:\Temp\2.jpg");
}

但是,大小仍然发生了变化。原始jpeg图像1.jpg的大小为1.88 MB (1,975,162 bytes)。重新保存为2.jpg 后,图像的大小变为1.86 MB (1,960,824 bytes)。

可能是什么问题?虽然 Matlab 向我保证图像的字节没有改变,但我想听你说Bitmap.Save 不应该改变图像的字节。

【问题讨论】:

  • 您可能希望使用 EXIF 库来更改元数据,而不是处理整个图像

标签: c# image bitmap jpeg


【解决方案1】:

JPEG 能够进行可变压缩,可以在压缩与原始保真度之间进行权衡。影响大小的因素包括:

  1. 特定的 JPEG 格式:连续或渐进。顺序在一次扫描中对组件的所有数据进行编码。渐进式在多次扫描中对组件进行编码。渐进式通常可以产生更大的压缩。但是,有许多设置适用于渐进式。

  2. 采样。 Jpeg 允许以低于 Y 分量的速率对 Cb 和 Cb 分量进行采样。如果您为每两个 Y(垂直和水平)采集一个 Cb 和 Cr 样本,则每 4 个 Y 样本将获得 1 个 Cb 和 CR 样本。这将要压缩的数据量从 12 个减半到 6 个。

  3. 量化表。量化表选择是JPEG压缩设置的主要形式。许多编码器将其隐藏在“质量”设置后面。

  4. 霍夫曼表。一些编码器使用预定义的霍夫曼表。如果编码器生成针对特定图像优化的 Huffman 表(更慢且工作量更大),您可以获得更好的压缩。

除非您使用与原始设置相同的设置重新压缩,否则您将获得不同的输出大小。即使您使用相同的设置,由于四舍五入,您通常会得出不同的值:JPEG 使用浮点计算,四舍五入为整数。

【讨论】:

    【解决方案2】:

    Jpeg 是一种压缩格式。它能够以不同的质量和不同的压缩格式保存。我的猜测是,两个图像的压缩级别设置不同。因为字节在读取时会被解压缩(无论压缩格式如何),因此字节将是相同的,即使它们的压缩方式不同。

    考虑一下,如果您使用 ZIP 格式压缩文件,然后使用 RAR 格式压缩相同的文件。两个文件大小不同,但是解压后里面的文件是一样的。

    您可以阅读有关如何为图像设置压缩级别here

    我正在复制链接中的代码以便于参考:

    private void VaryQualityLevel()
    {
        // Get a bitmap.
        Bitmap bmp1 = new Bitmap(@"c:\TestPhoto.jpg");
        ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg);
    
        // Create an Encoder object based on the GUID 
        // for the Quality parameter category.
        System.Drawing.Imaging.Encoder myEncoder =
            System.Drawing.Imaging.Encoder.Quality;
    
        // Create an EncoderParameters object. 
        // An EncoderParameters object has an array of EncoderParameter 
        // objects. In this case, there is only one 
        // EncoderParameter object in the array.
        EncoderParameters myEncoderParameters = new EncoderParameters(1);
    
        EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 50L);
        myEncoderParameters.Param[0] = myEncoderParameter;
        bmp1.Save(@"c:\TestPhotoQualityFifty.jpg", jpgEncoder, myEncoderParameters);
    
        myEncoderParameter = new EncoderParameter(myEncoder, 100L);
        myEncoderParameters.Param[0] = myEncoderParameter;
        bmp1.Save(@"c:\TestPhotoQualityHundred.jpg", jpgEncoder, myEncoderParameters);
    
        // Save the bitmap as a JPG file with zero quality level compression.
        myEncoderParameter = new EncoderParameter(myEncoder, 0L);
        myEncoderParameters.Param[0] = myEncoderParameter;
        bmp1.Save(@"c:\TestPhotoQualityZero.jpg", jpgEncoder, myEncoderParameters);
    
    }
    

    【讨论】:

    • 是否有打开、更改属性和保存相同质量的选项?
    • 您应该能够读取位图的编码器参数。然后就用上面的例子把参数设置成你从原文中读入的参数即可。
    • 问题是我不能使用bmp1.GetEncoderParameterList(jpgEncoder.Clsid);。它抛出一个异常。据我了解,此错误尚未在 Win7 中修复。还有其他建议吗?
    • 不是我的头顶。我会看看我能想出什么
    • JPEG 是一种有损格式(通常),因此无法仅因为“字节在读取时解压缩”而说字节相同。在这种情况下,它们是相同的,通常不是具有不同编码器/参数的连续压缩周期。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-08
    • 1970-01-01
    相关资源
    最近更新 更多