2010-02-13 19 views
10

Tengo algunos problemas con la rotación de imágenes en Java utilizando la clase AffineTransform.Problemas rotando BufferedImage

I tienen el siguiente método para la creación de un (90 grados) copia de una imagen girada:

private BufferedImage createRotatedCopy(BufferedImage img, Rotation rotation) { 
    int w = img.getWidth(); 
    int h = img.getHeight(); 

    BufferedImage rot = new BufferedImage(h, w, BufferedImage.TYPE_INT_RGB); 

    double theta; 
    switch (rotation) { 
     case CLOCKWISE: 
      theta = Math.PI/2; 
      break; 
     case COUNTERCLOCKWISE: 
      theta = -Math.PI/2; 
      break; 
     default: 
      throw new AssertionError(); 
    } 

    AffineTransform xform = AffineTransform.getRotateInstance(theta, w/2, h/2); 
    Graphics2D g = (Graphics2D) rot.createGraphics(); 
    g.drawImage(img, xform, null); 
    g.dispose(); 

    return rot; 
} 

La rotación es un enum simple con el NINGUNO valores, sentido horario y antihorario.

Los síntomas de mis problemas se muestran aquí:

http://perp.se/so/rotate_problems.html

Por lo tanto, la rotación funciona bien, pero las imágenes resultantes no están ancladas a las coordenadas correctas (o cómo se debe ponerlo). Y como realmente no sé qué diablos estoy haciendo en primer lugar (mi álgebra lineal es débil), no sé cómo resolver esto por mi cuenta.

Lo he intentado con algún truco aleatorio con la instancia de AffineTransform, pero no me ha ayudado (por supuesto). Intenté buscar en Google (y buscar SO), pero todos los ejemplos que he visto utilizan básicamente el mismo enfoque que yo ... lo que no funciona para mí.

Agradecido por su asesoramiento.

+1

pregunta equivalente para .NET: http://stackoverflow.com/questions/2225363/c-rotate-bitmap-90-degrees – finnw

Respuesta

16

Si tiene que expresar la transformada como una sola rotación, el punto de anclaje depende del sentido de giro: De cualquier (w/2, w/2) o (h/2, h/2).

Pero es probablemente más simple expresarlo como translate; rotate; translate, p. Ej.

AffineTransform xform = new AffineTransform(); 
xform.translate(0.5*h, 0.5*w); 
xform.rotate(theta); 
xform.translate(-0.5*w, -0.5*h); 

También puedes utilizar getQuadrantRotateInstance en lugar de getRotateInstance.

+0

Entiendo lo que dices, y lo he intentado también. El problema persiste, sin embargo.Todavía se están dibujando "fuera" del área objetivo, aunque en el "otro lado" horizontalmente, por así decirlo. Podría proporcionar algunas capturas de pantalla adicionales si no está claro a qué me refiero. – perp

+0

@perp, tienes razón, arreglado. He probado la nueva versión y funciona. – finnw

+0

¡Funciona como un encanto! Creo que tengo una mejor comprensión de lo que está sucediendo ahora, también. ¡Gracias! – perp

0

No sé si este podría ser su problema.

AffineTransform xform = AffineTransform.getRotateInstance(theta, w/2, h/2); 

¿Por qué no pruebas?

AffineTransform xform = AffineTransform.getRotateInstance(theta); 

O

g.transform(AffineTransform.getRotateInstance(theta)); 
g.drawImage(img, 0, 0, w/2, h/2, null, null); 
+0

he probado. :-) – perp

1

Puede probar una alternativa y crear un icono a partir de la imagen y luego usar Rotated Icon.

O puede probar este código antiguo que he encontrado en los foros de Sun:

import java.awt.*; 
import java.awt.geom.*; 
import java.awt.image.*; 
import java.io.*; 
import java.net.*; 
import javax.imageio.*; 
import javax.swing.*; 

public class RotateImage { 
    public static void main(String[] args) throws IOException { 
     URL url = new URL("https://blogs.oracle.com/jag/resource/JagHeadshot-small.jpg"); 
     BufferedImage original = ImageIO.read(url); 
     GraphicsConfiguration gc = getDefaultConfiguration(); 
     BufferedImage rotated1 = tilt(original, -Math.PI/2, gc); 
     BufferedImage rotated2 = tilt(original, +Math.PI/4, gc); 
     BufferedImage rotated3 = tilt(original, Math.PI, gc); 
     display(original, rotated1, rotated2, rotated3); 
    } 

    public static BufferedImage tilt(BufferedImage image, double angle, GraphicsConfiguration gc) { 
     double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle)); 
     int w = image.getWidth(), h = image.getHeight(); 
     int neww = (int)Math.floor(w*cos+h*sin), newh = (int)Math.floor(h*cos+w*sin); 
     int transparency = image.getColorModel().getTransparency(); 
     BufferedImage result = gc.createCompatibleImage(neww, newh, transparency); 
     Graphics2D g = result.createGraphics(); 
     g.translate((neww-w)/2, (newh-h)/2); 
     g.rotate(angle, w/2, h/2); 
     g.drawRenderedImage(image, null); 
     return result; 
    } 

    public static GraphicsConfiguration getDefaultConfiguration() { 
     GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 
     GraphicsDevice gd = ge.getDefaultScreenDevice(); 
     return gd.getDefaultConfiguration(); 
    } 

    public static void display(BufferedImage im1, BufferedImage im2, BufferedImage im3, BufferedImage im4) { 
     JPanel cp = new JPanel(new GridLayout(2,2)); 
     addImage(cp, im1, "original"); 
     addImage(cp, im2, "rotate -PI/2"); 
     addImage(cp, im3, "rotate +PI/4"); 
     addImage(cp, im4, "rotate PI"); 

     JFrame f = new JFrame("RotateImage"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.setContentPane(cp); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

    static void addImage(Container cp, BufferedImage im, String title) { 
     JLabel lbl = new JLabel(new ImageIcon(im)); 
     lbl.setBorder(BorderFactory.createTitledBorder(title)); 
     cp.add(lbl); 
    } 
} 
3

ya que sólo necesita 90 grados de rotación se puede evitar el uso de la materia AffineTransform:

public BufferedImage rotate90DX(BufferedImage bi) { 
    int width = bi.getWidth(); 
    int height = bi.getHeight(); 
    BufferedImage biFlip = new BufferedImage(height, width, bi.getType()); 
    for(int i=0; i<width; i++) 
     for(int j=0; j<height; j++) 
      biFlip.setRGB(height-1-j, width-1-i, bi.getRGB(i, j)); 
    return biFlip; 
} 

Esto también evita cortando bordes de imágenes rectangulares.

Desde: http://snippets.dzone.com/posts/show/2936

+3

Solo un aviso, forzando un acceso directo a los valores de píxel RGB saca la imagen de la tubería acelerada en Java2D. Este enfoque puede darle el resultado que desea, pero es mucho más lento. –

+0

Aha. No lo sabía Gracias –

+0

He probado este código y no solo gira la imagen, sino que también cambia a izquierda y derecha (como en un espejo) – Radon8472

Cuestiones relacionadas