Trabajo con imágenes con C#. Redimensionar una imagen.

Tras ponerle el borde a una imagen, y mezclar dos imágenes entre sí, ahora le toca el turno a redimensionar una imagen.

Empezaremos con el código completo, y obviaremos tanto el principio del código como el final, pues ambos están explicados en los dos artículos anteriores.

redimensionaImagen.cs
        public static MemoryStream Redimensiona(Stream imagen, int targetW, int targetH, int resolucion)
        {
            System.Drawing.Image original = System.Drawing.Image.FromStream(imagen);
            System.Drawing.Image imgPhoto = System.Drawing.Image.FromStream(imagen);

            // No vamos a permitir que la imagen final sea más grande que la inicial
            targetH = targetH <= original.Height ? targetH : original.Height;
            targetW = targetW <= original.Width ? targetW : original.Width;

            Bitmap bmPhoto = new Bitmap(targetW, targetH, PixelFormat.Format24bppRgb);

            // No vamos a permitir dar una resolución mayor de la que tiene
            resolucion = resolucion <= Convert.ToInt32(bmPhoto.HorizontalResolution) ? resolucion : Convert.ToInt32(bmPhoto.HorizontalResolution);
            resolucion = resolucion <= Convert.ToInt32(bmPhoto.VerticalResolution) ? resolucion : Convert.ToInt32(bmPhoto.VerticalResolution);

            bmPhoto.SetResolution(resolucion, resolucion);
            Graphics grPhoto = Graphics.FromImage(bmPhoto);
           
            grPhoto.SmoothingMode = SmoothingMode.AntiAlias;
            grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
            grPhoto.PixelOffsetMode = PixelOffsetMode.HighQuality;
            grPhoto.DrawImage(imgPhoto, new Rectangle(0, 0, targetW, targetH), new Rectangle(0, 0, original.Width, original.Height), GraphicsUnit.Pixel);
           
            MemoryStream mm = new MemoryStream();
            bmPhoto.Save(mm, System.Drawing.Imaging.ImageFormat.Jpeg);

            original.Dispose();
            imgPhoto.Dispose();
            bmPhoto.Dispose();
            grPhoto.Dispose();

            return mm;
        }

Lo primero que hacemos, como siempre, es recoger las Images desde los streams de entrada.

Ahora analicemos:

            // No vamos a permitir que la imagen final sea más grande que la inicial
            targetH = targetH <= original.Height ? targetH : original.Height;
            targetW = targetW <= original.Width ? targetW : original.Width;


Lo que estamos haciendo es redimensionar una imagen, pero lo que no queremos es que la imagen final sea más grande que la original. Esto se puede hacer o no, es a gusto de cada uno, pero a mí me gusta así , y además esta parte es bastante didáctica y puede servir para otros campos.

Como vemos, estamos comparando las dimensiones finales que queremos que tenga la imagen con las originales. Si son menores, las dejamos como estaban, pero si son mayores les dejamos el tamaño original.

Hacemos exactamente lo mismo con la resolución con este código

            // No vamos a permitir dar una resolución mayor de la que tiene
            resolucion = resolucion <= Convert.ToInt32(bmPhoto.HorizontalResolution) ? resolucion : Convert.ToInt32(bmPhoto.HorizontalResolution);
            resolucion = resolucion <= Convert.ToInt32(bmPhoto.VerticalResolution) ? resolucion : Convert.ToInt32(bmPhoto.VerticalResolution);

Ahora creamos el Bitmap con la resolución deseada y el graphic a partir de él:

            Bitmap bmPhoto = new Bitmap(targetW, targetH, PixelFormat.Format24bppRgb);

            bmPhoto.SetResolution(resolucion, resolucion);
            Graphics grPhoto = Graphics.FromImage(bmPhoto);


A continuación la configuración típica ya explicada en ponerle el borde a una imagen, y ahora vamos a lo importante:

            grPhoto.DrawImage(imgPhoto, new Rectangle(0, 0, targetW, targetH), new Rectangle(0, 0, original.Width, original.Height), GraphicsUnit.Pixel);

Analicemos los cuatro parámetros básicos:
1.- imgPhoto: la imagen que queremos redimensionar.
2.- new Rectangle(0, 0, targetW, targetH): esto indica las dimensiones del rectángulo final donde se va a colocar la imagen, de modo que el trozo de imagen que se coja se ajustará a este trozo. Fijaos que este es el truco de toda la cuestión.
3.- new Rectangle(0, 0, original.Width, original.Height): esto define el "trozo" del que hablábamos. En este caso queremos que se coja toda la imagen original, pero también podríamos coger el trocito que quisiéramos.
4.- GraphicsUnit.Pixel: indica que estamos trabajando en pixeles siempre.

Ahora ya sólo queda cerrarlo todo, devolver el MemoryStream y ya tenemos la imagen redimensionada!