Compresión de imágenes con .NET

No hace mucho que publicábamos un articulo en el que mostrábamos como construir un handler de ASP.NET para comprimir imágenes. El articulo estaba enfocado a modificar el tamaño de la imagen, reduciendo así su peso … pero no realizaba compresión de la misma.

En este articulo vamos a mostrar como aplicar una ratio de compresión a una imagen.

Combinar la reducción de tamaño y la compresión en un handler de ASP.NET puede ser una opción mas que interesante para optimizar nuestro ancho de banda, aunque requerirá de un trabajo extra por parte del procesador.

Para realizar la compresión vamos a hacer uso de las clases que nos provee el .NET Framework, en concreto el namespace System.Drawing. El programa tomará una imagen de entrada y como resultado de la ejecución tendremos una imagen comprimida a un determinado nivel de compresión.

image

Para el ejemplo hemos creado una pequeña aplicación de consola con Visual Studio 2008, que tomara una imagen del disco y la comprimirá al 70% de calidad.

static void Main(string[] args)
{
    ComprimirImagen(@"C:\img\robot.jpg", @"C:\img\robot_tratado.jpg", 70);
}

Como podemos ver todo el trabajo se realiza en el método ComprimirImagen , que mostramos a continuación.

static void ComprimirImagen(string inputFile, string ouputfile, long compression)
{

    Image image = Image.FromFile(inputFile);


    EncoderParameters eps = new EncoderParameters(1);
    eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, compression);


    string mimetype = GetMimeType(new System.IO.FileInfo(inputFile).Extension);
    ImageCodecInfo ici = GetEncoderInfo(mimetype);

    image.Save(ouputfile, ici, eps);

}

Simplemente creamos una nueva instancia de Image con el archivo de entrada, y posteriormente lo guardaremos utilizando una de las sobrecargas del método Save. En concreto esta, que recibe tres parámetros:

  • Nombre de archivo de salida.
  • ImageCodecInfo, una instancia de la clase ImageCodecInfo que proporciona la información necesaria sobre los codificadores y descodificadores (códecs) de imágenes instalados.
  • EncoderParameters, que represente el tipo y valor de los parámetros para el codec. En nuestro caso el tipo es la calidad (System.Drawing.Imaging.Encoder.Quality,) y el valor el ratio de compresion que queremos aplicar (70).

Para poder ejecutar esta sobrecarga del método Save, necesitamos obtener las instancias de ImageCodecInfo y de EncoderParameters. EncoderParameters en muy simple, solo tenemos que tener en cuenta que se trata de un array (aunque tenga un único elemento) y especificamos el parametro: la calidad de la imagen y su valor.

Image image = Image.FromFile(inputFile);
EncoderParameters eps = new EncoderParameters(1);
eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, compression);

Para obtener la instancia de ImageCodecInfo es un poco mas laborioso pero igual de sencillo, obtenemos el tipo mime  en función de la extension del archivo con la funcion GetMimeType, y posteriormente utilizamos ese valor para obtener la instancia de ImageCodeInfo de la colección de codecs disponibles - que nos proporciona ImageCodecInfo.GetImageEncoders();

static string GetMimeType(string ext)
{
    //    CodecName FilenameExtension FormatDescription MimeType 
    //    .BMP;*.DIB;*.RLE BMP ==> image/bmp 
    //    .JPG;*.JPEG;*.JPE;*.JFIF JPEG ==> image/jpeg 
    //    *.GIF GIF ==> image/gif 
    //    *.TIF;*.TIFF TIFF ==> image/tiff 
    //    *.PNG PNG ==> image/png 
    switch (ext.ToLower())
    {
        case ".bmp":
        case ".dib":
        case ".rle":
            return "image/bmp";

        case ".jpg":
        case ".jpeg":
        case ".jpe":
        case ".fif":
            return "image/jpeg";

        case "gif":
            return "image/gif";
        case ".tif":
        case ".tiff":
            return "image/tiff";
        case "png":
            return "image/png";
        default:
            return "image/jpeg";
    }
}

static ImageCodecInfo GetEncoderInfo(string mimeType)
{

    ImageCodecInfo[] encoders;
    encoders = ImageCodecInfo.GetImageEncoders();

    ImageCodecInfo encoder = (from enc in encoders
                      where enc.MimeType == mimeType
                      select enc).First() ;
    return encoder;
    
}

Hemos utilizado una consulta Linq para obtener el la instancia de ImageCodecInfo pero podemos hacerlo también con un bucle si trabajamos con versiones anteriores del framework.

El resultado de la ejecución del programa es una nueva imagen de la mitad del tamaño de la original , sin apenas perdida de calidad.

image El programa completo quedaría de la siguiente forma:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace ConsoleApplication12
{
    class Program
    {

        static void Main(string[] args)
        {
            ComprimirImagen(@"C:\img\robot.jpg", 
                            @"C:\img\robot_tratado.jpg", 
                            70);
        }

        static void ComprimirImagen(string inputFile, string ouputfile, long compression)
        {
         
            Image image = Image.FromFile(inputFile);
            EncoderParameters eps = new EncoderParameters(1);

            eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, compression);
            string mimetype = GetMimeType(new System.IO.FileInfo(inputFile).Extension);
            ImageCodecInfo ici = GetEncoderInfo(mimetype);

            image.Save(ouputfile, ici, eps);


        }

        static string GetMimeType(string ext)
        {
            //    CodecName FilenameExtension FormatDescription MimeType 
            //    .BMP;*.DIB;*.RLE BMP ==> image/bmp 
            //    .JPG;*.JPEG;*.JPE;*.JFIF JPEG ==> image/jpeg 
            //    *.GIF GIF ==> image/gif 
            //    *.TIF;*.TIFF TIFF ==> image/tiff 
            //    *.PNG PNG ==> image/png 
            switch (ext.ToLower())
            {
                case ".bmp":
                case ".dib":
                case ".rle":
                    return "image/bmp";

                case ".jpg":
                case ".jpeg":
                case ".jpe":
                case ".fif":
                    return "image/jpeg";

                case "gif":
                    return "image/gif";
                case ".tif":
                case ".tiff":
                    return "image/tiff";
                case "png":
                    return "image/png";
                default:
                    return "image/jpeg";
            }
        }

        static ImageCodecInfo GetEncoderInfo(string mimeType)
        {

            ImageCodecInfo[] encoders;
            encoders = ImageCodecInfo.GetImageEncoders();

            ImageCodecInfo encoder = (from enc in encoders
                              where enc.MimeType == mimeType
                              select enc).First() ;
            return encoder;
            
        }

    }
}

 

Saludos y hasta la próxima!

DJK

Pedro  Herrarte  Sánchez
Compresión de imágenes con .NET
Pedro Herrarte Sánchez

Pedro Herrarte, es consultor independiente, ofreciendo servicios de consultoría, análisis, desarrollo y formación. Posee mas de diez años de experiencia trabajando para las principales empresas de España. Es especialista en tecnologías .NET, entornos Web (ASP.NET, ASP.NET MVC,jQuery, HTML5), bases de datos (SQL Server y ORACLE) e integración de sistemas. Es experto en desarrollo (C#, VB.Net, T-SQL, PL/SQL, , ASP, CGI , C, Pro*C, Java, Essbase, Vignette, PowerBuilder y Visual Basic ...) y bases de datos (SQL Server y ORACLE). Pedro es MCP y MAP 2012, es fundador, diseñador y programador de www.devjoker.com..
Fecha de alta:08/04/2010
Última actualizacion:08/04/2010
Visitas totales:6334
Valorar el contenido:
Últimas consultas realizadas en los foros
Últimas preguntas sin contestar en los foros de devjoker.com