Trabajo con imágenes con C#. Ponerle un borde a una imagen

Trabajar con imágenes en C# para ASP.NET no es demasiado difícil, pero ni mucho menos trivial.

Los namespaces que se suelen utilizar para el trabajo con imágenes son System.Drawing, System.Drawing.Imaging y System.Drawing.Drawing2D.

Como siempre, un ejemplo vale más que horas de teoría, por lo que a lo largo de una serie de tres artículos estudiaremos los siguientes ejemplillos:
1. Ponerle el borde a una imagen
2. Mezclar dos imágenes
3. Redimensionar una imagen.

1. Ponerle el borde a una imagen.
El código completo del ejemplo es el siguiente:

trabajaImagenes.cs
        public static MemoryStream Borde(Stream imagen, Color color, float grosor)
        {
            System.Drawing.Image original = System.Drawing.Image.FromStream(imagen);
            System.Drawing.Image imgPhoto = System.Drawing.Image.FromStream(imagen);

            Bitmap bmPhoto = new Bitmap(original.Width, original.Height, PixelFormat.Format24bppRgb);
            Graphics grPhoto = Graphics.FromImage(bmPhoto);
            grPhoto.SmoothingMode = SmoothingMode.AntiAlias;
            grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
            grPhoto.PixelOffsetMode = PixelOffsetMode.HighQuality;

            Rectangle rec = new Rectangle(0, 0, original.Width, original.Height);
            grPhoto.DrawImage(imgPhoto, rec);
          
            Pen pen = new Pen(color, grosor);
            grPhoto.DrawRectangle(pen, rec);

            MemoryStream mm = new MemoryStream();
            bmPhoto.Save(mm, System.Drawing.Imaging.ImageFormat.Jpeg);

            // Cerramos todo lo cerrable
            original.Dispose();
            imgPhoto.Dispose();
            bmPhoto.Dispose();
            grPhoto.Dispose();

            return mm;
        }


Lo que hace este código es recibir el Stream de una imagen y dos parámetros de configuración del borde: su color y su grosor, de modo que se devuelve en un MemoryStream la imagen con el borde deseado.

El primer paso es recoger dos copias independientes de System.Drawing.Image.

            System.Drawing.Image original = System.Drawing.Image.FromStream(imagen);
            System.Drawing.Image imgPhoto = System.Drawing.Image.FromStream(imagen);


Lo pongo con el namespace entero porque es habitual equivocar este tipo Image con el WebControl  Image. De todos modos, este no es necesario hacerlo siempre que no se importe el namespace System.Web.UI.WebControls.

El segundo paso es crear un Graphics desde un Bitmap con las dimensiones originales de la imagen que pasamos como parámetro.

            Bitmap bmPhoto = new Bitmap(original.Width, original.Height, PixelFormat.Format24bppRgb);
            Graphics grPhoto = Graphics.FromImage(bmPhoto);

Las tres siguientes líneas de código no son más que opciones de configuración del Graphics merecedoras de un artículo entero. De momento nos vale con saber que son las habituales:

            grPhoto.SmoothingMode = SmoothingMode.AntiAlias;
            grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
            grPhoto.PixelOffsetMode = PixelOffsetMode.HighQuality;

Ahora viene lo interesante, pues con grPhoto.DrawImage vamos a crear realmente la imagen. Como vemos, utilizamos la función de dos parámetros, donde el primero es la imagen que vamos a dibujar y el segundo define la dimensión final de la imagen mediante un rectángulo:

            Rectangle rec = new Rectangle(0, 0, original.Width, original.Height);
            grPhoto.DrawImage(imgPhoto, rec);
  

Hasta este momento no tenemos más que la misma imagen que al principio, y es ahora cuando le ponermo el borde definiendo el Pen con el color y grosor especificados y finalmente haciendo un DrawRectangle con ese Pen y el Rectangle definido anteriormente

            Pen pen = new Pen(color, grosor);
            grPhoto.DrawRectangle(pen, rec);

Ahora ya no nos queda más que guardar el resultado en un MemoryStream, cerrar todo lo cerrable y devolver dicho MemoryStream.

            MemoryStream mm = new MemoryStream();
            bmPhoto.Save(mm, System.Drawing.Imaging.ImageFormat.Jpeg);

            // Cerramos todo lo cerrable
            original.Dispose();
            imgPhoto.Dispose();
            bmPhoto.Dispose();
            grPhoto.Dispose();

            return mm;


Pues ya está, espero que os haya servido de ayuda. Próximamente publicaré los artículos con los ejemplos prometidos para aclarar un poco más las ideas y dejar que, como siempre, sea vuestra imaginación la que os limite, no el desconocimiento de las herramientas.