2010-10-18 7 views
32

Me sorprendió mucho cuando cargué un archivo jpg y lo cambié con una calidad de 100 y el tamaño era casi 4 veces el original. Para seguir investigando, abrí y guardé sin establecer explícitamente la calidad y el tamaño del archivo era exactamente el mismo. Pensé que esto era porque nada había cambiado, así que solo estaba escribiendo los mismos bits en un archivo. Para probar esta suposición, dibujé una línea grande y gruesa en diagonal sobre la imagen y guardé nuevamente sin establecer la calidad (esta vez esperaba que el archivo saltara porque sería "sucio") pero disminuyó ~ 10Kb.¿Qué nivel de calidad utiliza Image.Save() para archivos jpeg?

En este momento, realmente no entiendo lo que sucede cuando simplemente llamo a Image.Save() sin especificar una calidad de compresión. ¿Cómo está tan cerca el tamaño del archivo (después de que se modificó la imagen) al tamaño original cuando aún no se establece la calidad cuando configuro la calidad a 100 (básicamente sin compresión) el tamaño del archivo es varias veces mayor que el original?

He leído la documentación sobre Image.Save() y no tengo ningún detalle sobre lo que está sucediendo detrás de las escenas. He buscado en Google de todas las formas en que puedo pensar, pero no puedo encontrar ninguna información adicional que explique lo que estoy viendo. He estado trabajando durante 31 horas seguidas, así que tal vez me falta algo obvio; 0)

Todo esto ha sucedido mientras implemento algunos métodos de biblioteca para guardar imágenes en una base de datos. Sobrecargué nuestro método "SaveImage" para permitir establecer explícitamente una calidad y durante mi prueba me encontré con los resultados impares (para mí) explicados anteriormente. Cualquier luz que puedas arrojar será apreciada.

Aquí hay un código que va a ilustrar lo que estoy experimentando:

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

Hice algunos experimentos sobre las compresiones para JPG en .NET y los errores correspondientes, véase http://www.c4real.biz/jpgCompression.aspx. –

+0

Según algunas pruebas rápidas, parece que su intuición original es correcta: si tiene una Imagen que originalmente era jpg y llama a Guardar sin especificar la calidad, simplemente vaciará los bits originales en el archivo. Si ha modificado la imagen en la memoria, o si solicita un nivel de compresión particular, volverá a codificar la imagen. Si solicita un nivel de alta calidad para una imagen que proviene de una fuente de baja calidad, está desperdiciando mucho espacio tratando de describir con mucha precisión todos los artefactos introducidos por la compresión original. – sethobrien

Respuesta

19

Utilizando el reflector, resulta que Image.Save() se reduce a la función GDI + GdipSaveImageToFile, con el encoderParams NULL. Así que creo que la pregunta es qué hace el codificador JPEG cuando obtiene un nulo encoderParams.Se ha sugerido el 75% aquí, pero no puedo encontrar ninguna referencia sólida.

EDITAR Probablemente se podría averiguar por sí mismo mediante la ejecución de su programa por encima de los valores de calidad de 1..100 y su comparación con el jpg guarda con la calidad predeterminada (usando, por ejemplo, fc.exe/B)

+0

¡Ah, me olvidé del reflector! ; 0) Es bueno saber que no hay magia misteriosa sucediendo en ese método. Creo que haré una prueba como me sugirió solo para tranquilizarme. Informaré los resultados aquí en este hilo. –

+7

Hice una prueba rápida y abrí un archivo * .bmp, luego guardé en jpg con la configuración predeterminada y también con una calidad establecida explícitamente en 75. Los archivos son EXACTAMENTE del mismo tamaño. Así que debe ser que el codificador está internamente en default a 75. Creo que esto debería estar en la documentación en alguna parte, ¿no? –

+0

Definitivamente, pero no estoy seguro * de qué documentación. Por lo que yo entiendo, es una característica del codificador predeterminado de Windows JPEG, cuya documentación reside en un lugar desconocido para mí ... –

5

IIRC, es del 75%, pero yo no recuerdo donde leí esto.

+0

75% es la compresión aceptada para mostrar en pantalla. – Stefanvds

+3

He usado su método para guardar como 75L y guardé otro con el predeterminado. Resultado: '75L = 36.7 KB' y' predeterminado = 36.8 KB'. Si no es el 75%, es como el 75.1% ... – BrunoLM

0

No sé mucho sobre el método Image.Save, pero puedo decir que agregar esa línea grasa lógicamente reducirá el tamaño de la imagen jpg. Esto se debe a la forma en que se guarda (y codifica) un jpg.

La línea negra gruesa proporciona una codificación muy simple y más pequeña (si mal no recuerdo esto es importante después de la transformación del coseno discreto), por lo que la imagen modificada se puede almacenar utilizando menos datos (bytes).

jpg encoding steps

En cuanto a los cambios en el tamaño (sin agregado de la línea), no estoy seguro de qué imagen se volvió a abrir y volver a guardar

Para investigar más a fondo abro y se guarda sin establecer explícitamente la calidad y el tamaño del archivo era exactamente el mismo

Si abrió la imagen anterior (tamaño normal original) y la volvió a guardar, entonces tal vez la compresión predeterminada y la compresión de la imagen original son lo mismo. Si abrió la nueva imagen (4 veces más grande) y la volvió a guardar, entonces la compresión predeterminada para el método de guardar se deriva de la imagen (como cuando se cargó).

Una vez más, no conozco el método guardar, así que solo estoy arrojando ideas (tal vez te darán una pista).

+0

Tienes razón, tiene perfecto sentido que una región grande y sólida se comprima de manera eficiente. Lo que estaba tratando de lograr y debería haber explicado mejor es forzar una nueva codificación de los datos. Estaba tratando de determinar si estaba viendo el mismo tamaño de archivo porque Save() estaba haciendo un volcado directo de bits al disco. Pensé que si pisoteaba la imagen y luego la guardaba, el archivo volvería a codificarse. Gracias por los enlaces y la información adicional. –

0

Cuando guarda una imagen como archivo JPEG con un nivel de calidad de < 100%, está introduciendo artefactos en la imagen guardada, que son un efecto secundario del proceso de compresión. Esta es la razón por la que volver a guardar la imagen al 100% aumenta el tamaño del archivo más allá del original; irónicamente, hay más información presente en el mapa de bits.

Esta es también la razón por la cual siempre debe intentar guardar en un formato sin pérdida (como PNG) si tiene la intención de editar el archivo posteriormente, de lo contrario afectará la calidad del resultado a través de múltiples transformaciones con pérdidas.

+0

Como tangente, también es importante guardar a una profundidad de color alta. Al realizar ciertas operaciones en imágenes, especialmente imágenes con degradados, es posible inducir la posterización. El uso de imágenes de origen de gran profundidad de color ayuda a suavizar los gradientes de color para que se mantenga suave. –

+0

Gracias por la información. Hice una prueba rápida en Photoshop para ver qué haría con esta imagen cuando se guardó en calidad 100 y, de hecho, aumentó el tamaño a casi lo mismo que mi prueba que hice en 100. –

Cuestiones relacionadas