【问题标题】:Quality of a saved JPG in C#在 C# 中保存的 JPG 的质量
【发布时间】:2010-12-01 20:51:19
【问题描述】:

我制作了一个小型 C# 应用程序来创建 .jpg 格式的图像。

pictureBox.Image.Save(name,ImageFormat.Jpeg);

图像已成功创建。我输入了一张原始图片,用它做一些事情并保存它。然而,这张新照片的质量低于原版。

有什么方法可以设置所需的质量吗?

【问题讨论】:

    标签: c# image-processing


    【解决方案1】:

    以下代码示例演示如何使用 EncoderParameter 构造函数创建 EncoderParameter。要运行此示例,请粘贴代码并调用 VaryQualityLevel 方法。

    此示例需要一个名为 TestPhoto.jpg 的图像文件,位于 c:。

    private void VaryQualityLevel()
    {
        // Get a bitmap.
        Bitmap bmp1 = new Bitmap(@"c:\TestPhoto.jpg");
        ImageCodecInfo jgpEncoder = 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", jgpEncoder, 
            myEncoderParameters);
    
        myEncoderParameter = new EncoderParameter(myEncoder, 100L);
        myEncoderParameters.Param[0] = myEncoderParameter;
        bmp1.Save(@"c:\TestPhotoQualityHundred.jpg", jgpEncoder, 
            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", jgpEncoder, 
            myEncoderParameters);
    
    }
    
    private ImageCodecInfo GetEncoder(ImageFormat format)
    {
        ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
        foreach (ImageCodecInfo codec in codecs)
        {
            if (codec.FormatID == format.Guid)
            {
                return codec;
            }
        }
        return null;
    }
    

    参考:http://msdn.microsoft.com/en-us/library/system.drawing.imaging.encoderparameter.aspx

    【讨论】:

    • 那行得通。似乎没有这一切,使用 50L 的标准质量。
    • EncoderParameter 可能使用非托管资源并且必须被释放。 Msdn 文档在这个主题上有点缺乏。它应该声明Param 数组是用空元素初始化的(所以在第一次分配给每个元素之前没有什么可以处理的),并且EncoderParameters 会自行处理其当前参数。
    • 这看起来不错,但是有没有办法获得原始图像质量(50L 或 60L..)?然后我们可以将其设置回来..
    • @Jordan - 这回答了与 Rajendra 提出的不同的问题。 Rajendra 询问是否有办法找出原始图像的质量设置,以便在输出时使用该质量。例如。如果文件最初是质量 100,则以质量 100 保存。如果文件是 Q 50,则以 50 保存。
    • 这是一个老Q,多年来吸引了一些高质量的答案。我推荐epox answerbytecode77's answer
    【解决方案2】:

    查看 MSDN 在how to set JPEG Compression level 上的文章。

    您需要使用另一个采用 ImageEncoder 及其参数的 Save() 重载。

    【讨论】:

      【解决方案3】:

      这是一个旧线程,但我已经重写了 Microsoft(根据 Dustin Getz 的回答)变得更有用 - 缩小 GetEncoderInfo 并在 Image 上进行扩展。 无论如何,没有什么新东西,但可能有用:

          /// <summary>
          /// Retrieves the Encoder Information for a given MimeType
          /// </summary>
          /// <param name="mimeType">String: Mimetype</param>
          /// <returns>ImageCodecInfo: Mime info or null if not found</returns>
          private static ImageCodecInfo GetEncoderInfo(String mimeType)
          {
              var encoders = ImageCodecInfo.GetImageEncoders();
              return encoders.FirstOrDefault( t => t.MimeType == mimeType );
          }
      
          /// <summary>
          /// Save an Image as a JPeg with a given compression
          ///  Note: Filename suffix will not affect mime type which will be Jpeg.
          /// </summary>
          /// <param name="image">Image: Image to save</param>
          /// <param name="fileName">String: File name to save the image as. Note: suffix will not affect mime type which will be Jpeg.</param>
          /// <param name="compression">Long: Value between 0 and 100.</param>
          private static void SaveJpegWithCompressionSetting(Image image, string fileName, long compression)
          {
              var eps = new EncoderParameters(1);
              eps.Param[0] = new EncoderParameter(Encoder.Quality, compression);
              var ici = GetEncoderInfo("image/jpeg");
              image.Save(fileName, ici, eps);
          }
      
          /// <summary>
          /// Save an Image as a JPeg with a given compression
          /// Note: Filename suffix will not affect mime type which will be Jpeg.
          /// </summary>
          /// <param name="image">Image: This image</param>
          /// <param name="fileName">String: File name to save the image as. Note: suffix will not affect mime type which will be Jpeg.</param>
          /// <param name="compression">Long: Value between 0 and 100.</param>
          public static void SaveJpegWithCompression(this Image image, string fileName, long compression)
          {
              SaveJpegWithCompressionSetting( image, fileName, compression );
          }
      

      【讨论】:

        【解决方案4】:

        如果您使用的是 .NET Compact Framework,另一种方法可能是使用 PNG 无损格式,即:

        image.Save(filename, ImageFormat.Png);
        

        【讨论】:

          【解决方案5】:

          下面是一段更紧凑的代码,用于保存为具有特定质量的 JPEG:

          var encoder = ImageCodecInfo.GetImageEncoders().First(c => c.FormatID == ImageFormat.Jpeg.Guid);
          var encParams = new EncoderParameters() { Param = new[] { new EncoderParameter(Encoder.Quality, 90L) } };
          image.Save(path, encoder, encParams);
          

          或者,如果 120 个字符宽的行对您来说太长:

          var encoder = ImageCodecInfo.GetImageEncoders()
                                      .First(c => c.FormatID == ImageFormat.Jpeg.Guid);
          var encParams = new EncoderParameters(1);
          encParams.Param[0] = new EncoderParameter(Encoder.Quality, 90L);
          image.Save(path, encoder, encParams);
          

          确保质量为long,否则您将获得ArgumentException

          【讨论】:

          • 进入我的代码库,非常感谢!
          • 另请参阅bytecode77's answer 以获取使用using 以确保Dispose 在最后及时发生的版本。
          【解决方案6】:

          使用无类型 GDI+ 样式 (https://msdn.microsoft.com/en-us/library/windows/desktop/ms533845(v=vs.85).aspx) 属性来设置 JPEG 质量看起来有点矫枉过正。

          直接的方式应该是这样的:

          FileStream stream = new FileStream("new.jpg", FileMode.Create);
          JpegBitmapEncoder encoder = new JpegBitmapEncoder();
          encoder.QualityLevel = 100;   // "100" for maximum quality (largest file size).
          encoder.Frames.Add(BitmapFrame.Create(image));
          encoder.Save(stream);
          

          参考:https://msdn.microsoft.com/en-us/library/system.windows.media.imaging.jpegbitmapencoder.rotation(v=vs.110).aspx#Anchor_2

          【讨论】:

          • 次要注意:由于最初的问题是关于低质量的投诉,因此使用最高质量来解决该问题:encoder.QualityLevel = 100
          【解决方案7】:

          被接受的社区 wiki 答案引用了 Microsoft 的示例。

          不过,为了节省你们的一些时间,我把它归结为精华,然后

          • 打包成合适的方法
          • 已实现IDisposable。我没有在任何其他答案中看到using (...) {。为了避免内存泄漏,最好的做法是处置所有实现IDisposable 的东西。

          public static void SaveJpeg(string path, Bitmap image)
          {
              SaveJpeg(path, image, 95L);
          }
          public static void SaveJpeg(string path, Bitmap image, long quality)
          {
              using (EncoderParameters encoderParameters = new EncoderParameters(1))
              using (EncoderParameter encoderParameter = new EncoderParameter(Encoder.Quality, quality))
              {
                  ImageCodecInfo codecInfo = ImageCodecInfo.GetImageDecoders().First(codec => codec.FormatID == ImageFormat.Jpeg.Guid);
                  encoderParameters.Param[0] = encoderParameter;
                  image.Save(path, codecInfo, encoderParameters);
              }
          }
          

          【讨论】:

          • 次要注意:显示质量的“95L”是一个很好的默认值,因为它接近“100L”的最大值,但对于非常详细的图像会节省一点文件大小。我通常使用“90L”到“100L”来保存高质量的质量,“70L”到“85L”可以获得不错的质量,但文件大小更合理。这还取决于您是否正在对文件进行“重复编辑”。如果是这样,请使用“100L”直到最后一次编辑(或在 .png 中进行无损编辑),然后以您需要的任何质量进行最终保存。
          猜你喜欢
          • 2012-07-15
          • 2012-05-11
          • 2018-02-16
          • 2013-02-09
          • 1970-01-01
          • 1970-01-01
          • 2011-05-20
          • 1970-01-01
          相关资源
          最近更新 更多