Trabajo con imágenes con C#. Mezclar dos imágenes

Tras ver en un artículo anterior cómo ponerle el borde a una imagen, ahora le toca el turno a realizar la mezclar de dos imágenes.

Empezamos con el código completo de la mezcla:

mezclaImagen.cs
        public static MemoryStream Mezcla(Stream imagenOrigen, Stream imagenSuperpuesta, double anchorelativo, double altorelativo, double posrelativaX, double posrelativaY, bool relativo)
        {
            // Convierte a image el fichero original y el que vamos a superponer
            System.Drawing.Image original = System.Drawing.Image.FromStream(imagenOrigen);
            System.Drawing.Image superpuesta = System.Drawing.Image.FromStream(imagenSuperpuesta);

            // Decidimos las dimensiones en base a si son relativas o absolutas
            double posicionX;
            double posicionY;
            double ancho;
            double alto;

            if (relativo)
            {
                posicionX = posrelativaX * original.Width;
                posicionY = posrelativaY * original.Height;
                ancho = anchorelativo * original.Width;
                alto = altorelativo * original.Height;
            }
            else
            {
                posicionX = posrelativaX;
                posicionY = posrelativaY;
                ancho = anchorelativo;
                alto = altorelativo;
            }

            // A mezclar se ha dicho
            System.Drawing.Image imgPhoto = System.Drawing.Image.FromStream(imagenOrigen);
            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, rec, GraphicsUnit.Pixel);
            grPhoto.DrawImage(superpuesta, new Rectangle((int)posicionX, (int)posicionY, (int)ancho, (int)alto), new Rectangle(0, 0, superpuesta.Width, superpuesta.Height), GraphicsUnit.Pixel);

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


Como vemos, es un ejemplo bastante completito, y no se limita sólo a la mezcla de dos simples imágenes, sino que tiene algunas características extra. Pero empecemos por el principio.

Vemos que las imágenes vienen en forma de stream como parámetros. Podríamos haberlo hecho de cualquier otro modo. Lo primero de todo es convertir a Image tanto el stream correspondiente al fichero de la imagen original como el de la imagen que vamos a superponer:

            // Convierte a image el fichero original y el que vamos a superponer
            System.Drawing.Image original = System.Drawing.Image.FromStream(imagenOrigen);
            System.Drawing.Image superpuesta = System.Drawing.Image.FromStream(imagenSuperpuesta);


Ahora tomaremos nuestra primera decisión. Está claro que queremos que la imagen original sea mezclada con la superpuesta, pero... ¿y si la imagen superpuesta es mayor que la original? Si así fuera y las mezcláramos a pelo, lo que ocurriría es que acabaríamos con un trozo de la imagen superpuesta y no se vería nada de la original. Para eso tenemos el segundo bloque de código.

            // Decidimos las dimensiones en base a si son relativas o absolutas
            double posicionX;
            double posicionY;
            double ancho;
            double alto;

            if (relativo)
            {
                posicionX = posrelativaX * original.Width;
                posicionY = posrelativaY * original.Height;
                ancho = anchorelativo * original.Width;
                alto = altorelativo * original.Height;
            }
            else
            {
                posicionX = posrelativaX;
                posicionY = posrelativaY;
                ancho = anchorelativo;
                alto = altorelativo;
            }


Como vemos, podemos decidir si queremos que la imagen superpuesta sea relativa a la original o no. Por ejemplo, si quisiéramos que la imagen superpuesta se pusiera en el centro de la imagen original con la mitad de las dimensiones de la imagen original, los valores correspondientes serían:

relativo = true;
anchorelativo = altorelativo = posrelativaX = posrelativaY = 0.5; // Ojalá se puediera hacer esto nen C#, ¿no? :P

Ahora viene lo importante: la mezcla. Los pasos previos son los mismos que el artículo anterior ponerle el borde a una imagen, por lo que no hace falta explicarlos. Lo interesante viene cuando llegamos a:

            Rectangle rec = new Rectangle(0, 0, original.Width, original.Height);
            grPhoto.DrawImage(imgPhoto, rec, rec, GraphicsUnit.Pixel);
            grPhoto.DrawImage(superpuesta, new Rectangle((int)posicionX, (int)posicionY, (int)ancho, (int)alto), new Rectangle(0, 0, superpuesta.Width, superpuesta.Height), GraphicsUnit.Pixel);


Como vemos, lo que hacemos es colocar en un Grafics (grPhoto) la imagen original tal cual y sobre ésta colocamos la imagen superpuesta, pero cambiándole las dimensiones a las que hayamos decidido previamente... ups! ¿He dicho redimensionar? Bien, eso vendrá en otro capítulo . Lo importante es que primero colocamos la imagen original dentro del graphics y después lo hacemos con la superpuesta.

Lo siguiente también es lo típico y que ya se explicó en anterior ponerle el borde a una imagen.

¡Espero que os haya servido de ayuda!