Search code examples
javaimagejava-2d

Java 2D rotate BufferedImage


This question was answered many time but I still can't apply it to my situation.

I want to rotate image on 90 degrees clockwise. I'm currently having following code:

private void writeImage(BufferedImage sourceImage, String Path) throws IOException {

        BufferedImage result;
        Graphics2D g;
        AffineTransform at = new AffineTransform();

        //Do some magic right here to correctly rotate the image itself
        if (sourceImage.getWidth() > sourceImage.getHeight()) {

        //Do some stuff that somehow works:
            result = new BufferedImage(sourceImage.getHeight(null), sourceImage.getWidth(null), BufferedImage.TYPE_INT_RGB);
            g = result.createGraphics();

            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// Anti-alias!
            g.translate((result.getHeight() - result.getWidth()) / 2, (result.getHeight() - result.getWidth()) / 2);
            g.rotate(Math.toRadians(90f), sourceImage.getHeight() / 2, sourceImage.getWidth() / 2);//simple try

        } else {
            result = new BufferedImage(sourceImage.getWidth(null), sourceImage.getHeight(null), BufferedImage.TYPE_INT_RGB);
            g = result.createGraphics();
        }

        //result = new BufferedImage(sourceImage.getWidth(null), sourceImage.getHeight(null), BufferedImage.TYPE_INT_RGB);
        //g = result.createGraphics();

        /*
        if (result.getWidth() > result.getHeight()) {

            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// Anti-alias!
            //g.translate(170, 0);
            g.rotate(Math.toRadians(90));
            //g.translate((result.getHeight() - result.getWidth()) / 4, (result.getHeight() - result.getWidth()) / 4);
            //g.rotate(Math.PI / 2, result.getHeight() / 2, result.getWidth() / 2);
            //g.drawImage(sourceImage, 0, 0, result.getHeight(), result.getWidth(), Color.WHITE, null);
            //AffineTransformOp op = new AffineTransformOp(rotateClockwise90(result), AffineTransformOp.TYPE_BILINEAR);
            //op.filter(sourceImage, result);

            int tempHeight = result.getHeight();
            int tempWidth = result.getWidth();

            BufferedImage rotated = resize(result, tempHeight, tempWidth);

            //result = rotated;

            result = resize(result, result.getHeight(), result.getWidth());
        }*/

        g.drawImage(sourceImage, 0, 0, result.getWidth(), result.getHeight(), Color.WHITE, null);
        //g.drawImage(sourceImage, at, null);
        g.dispose();

        //BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
        //g = bufferedImage.createGraphics();
        //Color.WHITE estes the background to white. You can use any other color
        //g.drawImage(image, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), Color.WHITE, null);

        File output = new File(Path);
        OutputStream out = new FileOutputStream(output);

        ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
        ImageOutputStream ios = ImageIO.createImageOutputStream(out);
        writer.setOutput(ios);

        ImageWriteParam param = writer.getDefaultWriteParam();
        if (param.canWriteCompressed()) {
            param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            param.setCompressionQuality(IMAGE_QUALITY);
        }

        writer.write(null, new IIOImage(result, null, null), param);


        out.close();
        ios.close();
        writer.dispose();
    }

Current Result

The source image and 'BufferedImage sourceImage' looks like this: Source Image

And what I expect to see is this: Expected

Thanks!


Solution

  • Here is a more general solution that will allow rotation of any specified degrees:

    import java.awt.*;
    import java.awt.geom.AffineTransform;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import javax.imageio.ImageIO;
    import javax.swing.*;
    import javax.swing.event.*;
    import javax.swing.border.*;
    
    public class Rotation
    {
        public static BufferedImage rotateImage(BufferedImage original, double theta)
        {
            //  Determine the size of the rotated image
    
            double cos = Math.abs(Math.cos(theta));
            double sin = Math.abs(Math.sin(theta));
            double width  = original.getWidth();
            double height = original.getHeight();
            int w = (int)(width * cos + height * sin);
            int h = (int)(width * sin + height * cos);
    
            //  Create empty image and fill in background
    
            BufferedImage rotated = new BufferedImage(w, h, original.getType());
            Graphics2D g2 = rotated.createGraphics();
            g2.setPaint(UIManager.getColor("Panel.background"));
            g2.fillRect(0, 0, w, h);
    
            //  Rotate the image
    
            double x = w/2;
            double y = h/2;
            AffineTransform at = AffineTransform.getRotateInstance(theta, x, y);
            x = (w - width)/2;
            y = (h - height)/2;
            at.translate(x, y);
            g2.drawRenderedImage(original, at);
            g2.dispose();
    
            return rotated;
        }
    
        private static void createAndShowGUI()
        {
            BufferedImage bi;
    
            try
            {
                String path = "mong.jpg";
                ClassLoader cl = Rotation.class.getClassLoader();
                bi = ImageIO.read( cl.getResourceAsStream(path) );
            }
            catch (Exception e) { return; }
    
            JLabel label = new JLabel( new ImageIcon( bi ) );
            label.setBorder( new LineBorder(Color.RED) );
            label.setHorizontalAlignment(JLabel.CENTER);
    
            JPanel wrapper = new JPanel();
            wrapper.add( label );
    
            JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 360, 0);
            slider.addChangeListener(new ChangeListener()
            {
                public void stateChanged(ChangeEvent e)
                {
                    int value = slider.getValue();
                    BufferedImage rotated = Rotation.rotateImage(bi, Math.toRadians(value) );
                    label.setIcon( new ImageIcon(rotated) );
                }
            });
    
            JFrame frame = new JFrame("Rotation");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(wrapper, BorderLayout.CENTER);
            frame.add(slider, BorderLayout.PAGE_END);
            frame.setSize(600, 600);
            frame.setLocationByPlatform( true );
            frame.setVisible( true );
        }
    
        public static void main(String[] args)
        {
            java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
        }
    }