2009-09-27 14 views
53

Creé una pequeña aplicación C# para crear una imagen en formato .jpg.Calidad de un JPG guardado en C#

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

La imagen se ha creado con éxito. Ingresé una foto original, hago algunas cosas con ella y la guardo. La calidad de esta nueva imagen, sin embargo, es inferior a la del original.

¿Hay alguna manera de establecer la calidad deseada?

Respuesta

71

El siguiente ejemplo de código muestra cómo crear un EncoderParameter utilizando el constructor EncoderParameter. Para ejecutar este ejemplo, pegue el código y llame al método VaryQualityLevel.

Este ejemplo requiere un archivo de imagen llamado TestPhoto.jpg ubicado en 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; 
} 

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

+2

que funciona. Parece que sin todo esto, se usa una calidad estándar de 50L. – KdgDev

+0

Tiene un error tipográfico. jgpEncoder cuando se refería a jpgEncoder;) –

+0

EncoderParameter puede usar recursos no administrados y debe desecharse. La documentación de MSDN es un poco escasa en este tema. Debe indicar que la matriz 'Param' se inicializa con elementos nulos (por lo tanto, no hay nada que desechar antes de la primera asignación a cada elemento), y que' EncoderParameters' dispone de sus parámetros actuales por su cuenta. –

13

Este es un hilo viejo, pero he reescrito Microsoft (según la respuesta de Dustin Getz) para que sea un poco más útil, reduciendo GetEncoderInfo y haciendo una extensión en Image. De todos modos nada realmente nuevo, pero puede ser de utilidad:

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

Si está utilizando .NET Compact Framework, una alternativa podría ser utilizar el formato sin pérdidas PNG es decir:

image.Save(filename, ImageFormat.Png); 
30

He aquí una incluso más compacto trozo de código para guardar en formato JPEG con una calidad específica:

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

O, si 120 caracteres de ancho líneas son demasiado largas para usted:

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

Asegúrese de que la calidad es un long o se obtendrá un ArgumentException!

+0

Yendo directamente a mi biblioteca de código ¡muchas gracias! – JustJohn

+0

Consulte también [respuesta de bytecode77] (https://stackoverflow.com/a/39493346/199364) para obtener una versión de esto que usa 'using' para asegurarse de que 'Dispose' suceda inmediatamente al final. – ToolmakerSteve

4

Uso de atributos sin tipo de estilo GDI + (https://msdn.microsoft.com/en-us/library/windows/desktop/ms533845(v=vs.85).aspx) para configurar la calidad JPEG parece excesivo.

Una forma directa debe tener este aspecto:

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

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

+0

Nota secundaria: dado que la pregunta original era una queja sobre la baja calidad, para resolver esa calidad máxima de uso: 'encoder.QualityLevel = 100'. – ToolmakerSteve

3

El wiki de respuesta de la comunidad, la cual es aceptada, referrs a un ejemplo de Microsoft.

Sin embargo, con el fin de ahorrar algo de tiempo que, Herví hacia abajo a una esencia y

  • lo embaló en un método adecuado
  • Implementado IDisposable. No he visto using (...) { en ninguna otra respuesta.Para evitar fugas de memoria, lo mejor es desechar todo lo que implemente 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); 
    } 
} 
+0

Nota secundaria: "95L" como se muestra para la calidad es un buen valor predeterminado porque está cerca del máximo de "100L", aunque se guardará un poco en el tamaño del archivo, para imágenes muy detalladas. Normalmente utilizo "90L" a "100L" para la conservación de calidad alta, "70L" a "85L" para una calidad decente, pero un tamaño de archivo más razonable. Depende también de si está realizando una "edición repetida" de un archivo. Si es así, use "100L" hasta la última edición (o edite en .png para que no tenga pérdidas), luego haga el último guardado con la calidad que necesite. – ToolmakerSteve

Cuestiones relacionadas