Rotar imágenes según sus metadatos de orientación

¡Hola!

Hay herramientas que se te ocurren pensando en qué cosas podrían ser útiles; y otras que surgen cuando te topas con un problema y dices: ¡joder, seguro que hay alguna solución para esto!

El otro día, mi mujer, @amaterasu_n estaba escribiendo en su blog de mami the vikings mama un post, y quería poner algunas fotos. Al ser ciegos, el tema de las imágenes en los posts es algo complejo. Nunca sabemos si la foto ha quedado bien, o se corta, o se descentra… así que después de ponerlas en el post, preguntamos a una compañera de trabajo, y me dijo que había fotos que estaban giradas… Ya os podéis imaginar, la típica foto tomada en horizontal, y que necesitas girar para que no tengas que darle la vuelta a la pantalla.

Así que me dije: Los smartphones tienen acelerómetros y giroscopios para detectar el cambio de orientación y adaptar las interfaces a esos cambios. ¿No guardarán esta información en los metadatos exif de las fotos? Y sorprendentemente, ¡la respuesta es sí! Imagino que también habrá cámaras que lo hacen, pero no he podido comprobarlo.

Buscando un poco por internet, me encontré con ExifExtractor, una pequeña librería en c# que me permitía extraer los datos exif de las imágenes. Por otro lado, en este artículo sobre las etiquetas exif encontré los valores y significados de esta etiqueta…

¡Problema resuelto!

He desarrollado una pequeñísima aplicación en c# que dada una imagen, extrae la orientación, la rota o voltea (rotate / flip) en consecuencia e informa al usuario de la operación que ha realizado sobre ella.

Podéis descargar la herramienta FixPictureOrientation desde este enlace.

Solo tenéis que descomprimirlo en alguna carpeta, ejecutar el exe y pulsar el botón de abrir y corregir foto, buscar la foto, abrirla… ¡y ya está!

Nota: Para ejecutar el programa deberéis tener instalado el .NET Framework 4 (si usáis Windows 7 o superior ya viene por defecto, y si no, casi seguro que lo tenéis de todos modos 😉 Si no fuera así, podéis descargar el instalador del .NET Framework 4 desde este enlace

El código c# es muy sencillo (obviando toda la parte de la extracción de datos Exif, cuyo código podéis encontrar en el sitio de codeproject que os puse arriba:

using Goheer.EXIF;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace FixPictureOrientation
{
	public partial class FrmPrincipal : Form
	{
		public FrmPrincipal()
		{
			InitializeComponent();
		}

		private void BtnCorregir_Click(object sender, EventArgs e)
		{
			OpenFileDialog dlg = new OpenFileDialog()
			{
				Filter = "Archivos de imagen JPG (*.jpg)|*.jpg",
				Title = "Abrir foto",
				ShowReadOnly = false,
				ShowHelp = false,
				InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyComputer),
				CheckFileExists = true
			};
			DialogResult res = dlg.ShowDialog();
			if (res == DialogResult.Cancel) return;
			var rutaImagen = dlg.FileName;
			// Rotamos la imagen de acuerdo a los datos de exif
			Bitmap bmp;
			try
			{
				bmp = new Bitmap(rutaImagen);
			}
			catch (Exception)
			{
				MessageBox.Show("¡Pero qué me has dado! Esto no parece una imagen válida!", "¡Esto no se come!", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}
			try
			{
				var exif = new EXIFextractor(ref bmp, Environment.NewLine);
				if (exif["Orientation"] != null)
				{
					int iOrientacion;
					if (!Int32.TryParse(exif["Orientation"].ToString(), out iOrientacion))
					{
						MessageBox.Show("Los datos de orientación parecen no ser correctos. ¡Disculpa!", "Uups!", MessageBoxButtons.OK, MessageBoxIcon.Error);
						return;
					}
					string rotado;
					RotateFlipType tipoRotacion = GetDesiredRotation(iOrientacion, out rotado);
					if (tipoRotacion == RotateFlipType.RotateNoneFlipNone)
					{
						MessageBox.Show("¡Esta foto no necesita ninguna rotación! ¡Puedes usarla sin problemas!", "¡Esta ya está!", MessageBoxButtons.OK, MessageBoxIcon.Information);
						return;
					}

					bmp.RotateFlip(tipoRotacion);
					var equivalenciasExif = new Goheer.EXIF.translation();
					int idOrientacion = equivalenciasExif.Keys.OfType<int>().FirstOrDefault(k => equivalenciasExif[k].ToString() == "Orientation");
					// Reajustamos la propiedad de orientación para que coincida con la orientación actual.
					bmp.RemovePropertyItem(idOrientacion);
					exif.setTag(idOrientacion, "1");
					bmp.Save(rutaImagen, ImageFormat.Jpeg);
					MessageBox.Show($"¡Perfecto! La imagen se ha rotado {rotado}.", "¡Listo!", MessageBoxButtons.OK, MessageBoxIcon.Information);
				}
				else
				{
					MessageBox.Show("Lo siento, no hay datos de orientación en los metadatos de la foto... ¡No puedo detectar la posición de la fotografía!", "Me cachis!", MessageBoxButtons.OK, MessageBoxIcon.Information);
				}
			}
			catch (Exception ex)
			{
				MessageBox.Show($"Se produjo un error inesperado: {ex.Message}.", "Uuups.", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
			finally
			{
				if (bmp != null) bmp.Dispose();
			}
		}
		
		private void BtnSalir_Click(object sender, EventArgs e)
		{
			this.Close();
		}

		/// <summary>
		///  Devuelve la rotación que habría que realizar para que la foto rote a la posición adecuada en función del dato de orientación EXIF
		/// </summary>
		/// <param name="orientation"> Valor numérico de orientación que indica la orientación actual de la foto</param>
		/// <param name="rotationExplanation">Explicación de qué rotación se va a realizar</param>
		/// <returns>Uno de los valores de la enumeración RotateFlipType indicando la rotación que se debe aplicar</returns>
		private static RotateFlipType GetDesiredRotation(int orientation, out string rotationExplanation)
		{
			RotateFlipType rotationType;
			switch (orientation)
			{
				case 1: // fila 0 = arriba, columna 0 = lado izquierdo
					rotationExplanation = "0 grados";
					rotationType = RotateFlipType.RotateNoneFlipNone;
					break;
				case 2: // fila 0 = arriba, columna 0 = lado derecho
					rotationExplanation = "0 grados y volteo horizontal";
					rotationType = RotateFlipType.RotateNoneFlipX;
					break;
				case 3: // fila 0 = abajo, columna 0 = lado derecho
					rotationExplanation = "180 grados en sentido horario";
					rotationType = RotateFlipType.Rotate180FlipNone;
					break;
				case 4: // fila 0 = abajo, columna 0 = lado izquierdo
					rotationExplanation = "180 grados en sentido horario y volteo horizontal";
					rotationType = RotateFlipType.Rotate180FlipX;
					break;
				case 5: // fila 0 = lado izquierdo, columna 0 = arriba
					rotationExplanation = "90 grados en sentido horario y volteo horizontal";
					rotationType = RotateFlipType.Rotate90FlipX;
					break;
				case 6: // fila 0 = lado derecho, columna 0 = arriba
					rotationExplanation = "90 grados en sentido horario";
					rotationType = RotateFlipType.Rotate90FlipNone;
					break;
				case 7: // fila 0 = lado derecho, columna 0 = abajo
					rotationExplanation = "270 grados en sentido horario y volteo horizontal";
					rotationType = RotateFlipType.Rotate270FlipX;
					break;
				case 8: // fila 0 = lado izquierdo, columna 0 = abajo
					rotationExplanation = "270 grados en sentido horario";
					rotationType = RotateFlipType.Rotate270FlipNone;
					break;
				default:
					rotationExplanation = "0 grados";
					rotationType = RotateFlipType.RotateNoneFlipNone;
					break;
			}
			return rotationType;
		}

	}
}

¡Espero que os sea útil!

¡Un saludo!

Entrada visitada 648 veces

2 pensamientos sobre “Rotar imágenes según sus metadatos de orientación”

  1. ¡Hola! aquí la susodicha primera tester.
    Tengo que decir que efectivamente me fue perfecta la mini app para corregir la orientación de las fotos.
    Tengo claro que por mucho que me pese o me deje de pesar, los blogs llaman más la atención si contienen imágenes por lo tanto, quiero ser capaz cuando lo considere, de poner fotos en mis blogs sin que se vean mal o tenga que estar pidiendo ayuda por ello.
    Ahora por fin ya puedo, gracias a la app que me hizo Juanjo para iPhone que me permite etiquetar las fotos cuando se toman y ahora con el fix picture orientation, sé qué foto estoy poniendo y sé que se verá de manera correcta.

    ¡Muchas gracias por facilitarnos las pequeñas cosas guapo!

    PD: Releyéndome me parece tanto este comentario a los de las webs con productos de usuarios 100% satisfechos… 😛

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *