Rotar una imagen en Java

Rotar Imagen en java

Recientemente he estado trabajando en un proyecto en el que tenía que hacer ciertas manipulaciones sobre imágenes. Una de las operaciones que se requerían era la rotación de las mismas.

La operación en sí es algo más compleja de lo que pueda parecer, por dos razones. En primer lugar porque no solo hay que rotar la imagen sino desplazarla dentro del sistema de coordenadas para conservar las esquinas de la misma, y en segundo lugar porque hay que tener en cuenta los diferentes ángulos de rotación posibles, las esquinas del giro no serán las mismas en los diferentes ángulos.

Buscando por Internet llegué a varias posibles soluciones pero no tenían en cuenta el tema de los diferentes ángulos, solo funcionaban hasta giros de 90 grados, y respecto a la traslación de la imagen para conservar las esquinas no en todos los ejemplos que vi se tenía en cuenta. He decidido explicar el procedimiento que he seguido puesto que las ideas de Internet me ayudaron pero no encontré la solución que tuviera en cuenta los dos problemas comentados; por ello me parece interesante presentar la manera en que logré resolver como rotar una imagen en java.

Introducción

Para realizar las transformaciones de las imágenes usaremos la clase Java llamada AffineTransform que nos servirá para escalar una imagen, rotarla y trasladarla.

Para la rotación de una imagen tendremos que saber los grados (radianes) que se desea rotar y respecto a que, la rotación en la mayoría de los casos será respecto al centro de la imagen, para ello tendremos que saber en ancho y el alto de la imagen.

En la operación de traslación habrá que ver donde quedan las esquinas de las imágenes en los ejes X e Y dependiendo de los ángulos de rotación de la imagen. Lo que yo hice para comprenderlo fue dibujarme en un papel un rectángulo con las esquinas de colores e ir girándolo para ver donde quedaban después de los giros, algo parecido a lo que os trato de ilustrar a continuación.

Esquema rotar una imagen en java

Rotar una imagen en Java con AffineTransform

Una vez visto el planteamiento del problema “sobre el papel” ya podemos pasar a ver como hacerlo en Java.

En mi caso lo que hice fue construir una clase que tuviera todo lo necesario para hacer las transformaciones con imágenes. La clase tiene como atributos las dimensiones de la imagen en pixeles y un objeto de la clase AffineTransform, el atributo de los grados vendrá dado en grados sexagesimales que habrá que pasar posteriormente a radianes.

Una vez vistos los atributos de la clase Java vamos a ver el método de rotación de una imagen. Veremos que se pasan los grados a radiantes con el método estático de la clase Math y se toma como punto de referencia para la rotación el centro de la imagen que será el ancho y alto de la misma dividido entre dos.

Después de la rotación nos faltará el paso de la traslación como ya hemos comentado. Lo que hará este método es obtener la traslación que se ha de hacer de la imagen dentro del sistema de coordenadas de la misma dependiendo de la rotación para conservar las cuatro esquinas de la misma dentro del rectángulo de la imagen.

Para la realización de esto veremos que lo que se hace es ver las coordenadas X e Y en las que quedan las esquinas de la imagen que darán la coordenada (0,0) del sistema de coordenadas después de haber rotado la imagen porque como vemos se usa el objeto AffineTransform at que fue el mismo sobre el que ya se aplicó la rotación. Una vez hecho esto vemos que se usa otro objeto AffineTransform para hallar la traslación y se une con el que se había usado para la rotación.

Para hacer diferencia entre los ángulos de rotación veremos los métodos que hayan que puntos de la imagen son los que darán la coordenada (0,0) de la imagen, estos datos se obtienen muy fácilmente del esquema que les he presentado en la introducción.

Por ejemplo para una rotación de entre 90 y 180 grados.

  • El punto A será el azul que será (0, altoImagen)
  • El punto B será el rojo que será (anchoImagen, altoImagen)

Aplicaremos esto para el resto de los casos y veremos que nos quedará un código como el que presento a continuación.

Pues con esto ya estaría acabado, ahora cada vez que queramos rotar una imagen lo podemos hacer con un método estático como el que les enseño a continuación.

Esto dará como resultado un BufferedImage con la imagen rotada y la zona de no datos en negro. Llamamos zona de no datos a la zona que se ha quedado sin información de la imagen ya que está estará encerrada en un rectángulo aunque este rotada (lo podemos ver en la imagen que abre el artículo).

Guardado de la Imagen

Si queremos guardar la imagen será algo tan sencillo como esto.

Lectura de la Imagen

También para los que deseen leer una imagen en Java les dejo el siguiente código. El siguiente código les puede servir para leer una imagen en formato JPEG. Este método es importante puesto que para que funcione bien la rotación debe de estar en un BufferedImage de tipo RGB.

Proyecto de ejemplo

Dejo a vuestra disposición un proyecto de NetBeans totalmente funcional. En el proyecto de ejemplo se usa exactamente el mismo código que ha sido explicado en este artículo. El proyecto tiene un método main preparado para leer una imagen, rotar la imagen y finalmente guardarla.

Proyecto Netbeans de ejemplo para Rotar una imagen en Java usando AffineTransformProyecto Netbeans. Rotar una imagen en Java usando AffineTransform


En el próximo tutorial os enseñaré como hacer transparente la zona de no datos de la imagen (toda la zona negra) y guardar la imagen como PNG que es un formato que conserva la transparencia de la imagen.

Espero que les haya sido de utilidad esta guía para rotar imágenes en Java. Si alguien tiene alguna duda que no dude en dejar un comentario. Me despido hasta la próxima publicación.

Actualización (9 de Abril de 2014): Después de ver en los comentarios que había personas a las que no les funcionaba este método de rotación he investigado el asunto y he visto que es importante la manera en la que la imagen es leída. Por ello he actualizado el artículo con el código correspondiente para la lectura de la imagen.

Actualización (20 de Octubre de 2014): Después de algunos comentarios recibidos he decido ayuda un poco más al público y he subido un proyecto de ejemplo totalmente funcional sobre como rotar imágenes con el código que se puede ver en el post.


16 Comentarios

  1. Marco

    No podrías poner las líneas que se deben colocar en el main para ejecutar la aplicación??

    • Hola Marco:

      He subido un proyecto de ejemplo totalmente funcional en el que puedes ver una clase main que lee la imagen, luego la rota y finalmente la guarda.

      Al final del post puedes ver el proyecto de ejemplo. Si sigues teniendo problemas no dudes en comentar. Un saludo!

  2. gabriel

    che, tirè el codigo en el NetBeans y me dice que me falta hacer algo que no
    no main classes found

    • Este error normalmente se da cuando se genera un Jar y no se designa ninguna clase como main para que inicie el Jar.
      No obstante con la poca información que me das sobre lo que has hecho no puedo ayudarte demasiado. En principio el código que yo he dado es para un propósito concreto. No es una aplicación completa como tal.
      Un saludo!

  3. Mathías

    Me anduvo de maravilla, muchas gracias!

    • Muchas gracias por el comentario. Me alegro de que funcionara correctamente 🙂 Un saludo!

  4. Alejandro Ruiz

    Tu metodo no tira ni pa atrás! esto es lo que he añadido y me sale este error (llevo como 2 horas viendo que le pasa y na!):

    private static void saveJPGImage(BufferedImage im) throws IOException {
    ImageIO.write(im, "JPG", new File("imagen.jpg"));
    }

    public static void Rotar(int grados, String path) throws IOException{
    File f = new File(path);
    BufferedImage image = ImageIO.read(f);
    image=rotacionImagen(image, grados);
    saveJPGImage(image);
    }

    public static void main(String[] args) throws IOException {
    // TODO Auto-generated method stub
    Rotar(90,"/Users/SICOT/Desktop/Stonehenge.jpg");
    }

    Sale la siguiente excepción
    Exception in thread "main" java.awt.image.ImagingOpException: Unable to transform src image
    at java.awt.image.AffineTransformOp.filter(AffineTransformOp.java:267)
    at ImageTransform.rotacionImagen(ImageTransform.java:82)
    at ImageTransform.Rotar(ImageTransform.java:92)
    at ImageTransform.main(ImageTransform.java:98)

    • Hola Alejandro:

      He actualizado el artículo con el método de lectura. Para que funcione la lectura la imagen ha de estar en formato RGB. Usa el método de lectura que te he puesto en el artículo.

      He estado haciendo pruebas y me ha funcionado perfectamente leyendo la imagen de esa forma. Confírmame que te funciona por favor.

      Un saludo!

  5. Victor

    Hola, muy buen trabajo me esta sirviendo de mucha ayuda pero tengo un problema al ejecutarlo me salta una excepción en ato.filter, he leído que esta puede darse por problemas en el formato pero el formato que utilizo es jpg por lo que no daría problema. Como no sea de la forma que meto en el buffer, lo realizo así:
    File ruta= new File(ruta_imagen);
    BufferedImage Image=ImageIO.read(ruta);
    donde ruta_imagen es un string.

    Sabrías decirme como puedo solucionarlo?

    Saludos

    • Hola Víctor:
      En teoría la forma en que lees la imagen es correcta. Respecto al error que me cuentas no te puedo ayudar si no me dices la excepción que te da. Yo el código que he publicado lo he copiado de una aplicación hecha por mi que funciona correctamente por lo que no debería de fallar, la única diferencia es que yo usaba imágenes en formato TIFF pero debería de dar igual ya que una vez leídas están en un BufferedImage. ¿Has intentado con otras imágenes?

      Un saludo!

    • victor

      La excepcion

      Exception in thread “main” java.awt.image.ImagingOpException: Unable to transform src image
      at java.awt.image.AffineTransformOp.filter(Unknown Source)

    • Hola Víctor:

      He estado probando el código de la aplicación que lo usa y funciona perfectamente, creo que tu error a lo mejor puede ser debido al formato de imagen o al esquema de color. Intenta probar con otras imágenes y dime si te funciona.

      Si sigues con el problema te muestro como hacía yo la lectura de la imagen aunque es muy parecida a la que me mostraste que hacías tu.

      Un saludo!

  6. Gabriel

    Muchas gracias Muy bueno me funciona perfecto!

  7. Francisco

    la rotacion cambia los colores de la imagen, hay alguna forma de corregirlo?

    • Hola Francisco:
      Si se cambian los colores de la imagen probablemente sea un problema en el modo en que lees la imagen y luego la escribes. Me explico, al leer una imagen normalmente la lees con un modelo de color.
      La imagen que tu creas para guardar la imagen rotada se crea en esta línea por lo que en teoría como ves se crea una con el mismo modelo de color que en el origen.
      destinationImage = ato.createCompatibleDestImage(origen, origen.getColorModel());
      A mi me pasaba cuando estaba aprendiendo a hacer la rotación y la línea que te muestro me solucionó el problema. Si no te funciona con esa línea prueba tú a crear la imagen de destino con el tipo igual que en la lectura, pero ten en cuenta que esa línea también te crea la imagen de destino del tamaño correcto. Te dejo un enlace a la API de java sobre esa función.
      http://docs.oracle.com/javase/7/docs/api/java/awt/image/AffineTransformOp.html#createCompatibleDestImage(java.awt.image.BufferedImage, java.awt.image.ColorModel)

      Si te sigue sin funcionar después de ver esto a lo mejor el problema lo tienes en la forma en que haces la lectura de la imagen. Si te sigue dando problemas te cuento la manera en que hice yo la lectura.

      Saludos

Trackbacks/Pingbacks

  1. Bitacoras.com - Información Bitacoras.com... Valora en Bitacoras.com: Recientemente he estado trabajando en un proyecto en el que tenía que hacer ciertas…

Deja un comentario

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.

A %d blogueros les gusta esto: