Rotate an Icon in Java


One user asked us to add a method to IconsFactory to rotate an icon for any angle. Sounds like a simple thing to do but it took me a while to get it right. It is checked in to JIDE Common Layer as part of 2.2.2 release. See below for the complete source. Feel free to use it.

final static double DEGREE_90 = 90.0 * Math.PI / 180.0;

    /**
     * Creates a rotated version of the input image.
     *
     * @param c            The component to get properties useful for painting, e.g. the foreground
     *                     or background color.
     * @param icon         the image to be rotated.
     * @param rotatedAngle the rotated angle, in degree, clockwise. It could be any double but we
     *                     will mod it with 360 before using it.
     *
     * @return the image after rotating.
     */

    public static ImageIcon createRotatedImage(Component c, Icon icon, double rotatedAngle) {
        // convert rotatedAngle to a value from 0 to 360
        double originalAngle = rotatedAngle % 360;
        if (rotatedAngle != 0 && originalAngle == 0) {
            originalAngle = 360.0;
        }

        // convert originalAngle to a value from 0 to 90
        double angle = originalAngle % 90;
        if (originalAngle != 0.0 && angle == 0.0) {
            angle = 90.0;
        }

        double radian = Math.toRadians(angle);

        int iw = icon.getIconWidth();
        int ih = icon.getIconHeight();
        int w;
        int h;

        if ((originalAngle >= 0 && originalAngle <= 90) || (originalAngle > 180 && originalAngle <= 270)) {
            w = (int) (iw * Math.sin(DEGREE_90 - radian) + ih * Math.sin(radian));
            h = (int) (iw * Math.sin(radian) + ih * Math.sin(DEGREE_90 - radian));
        }
        else {
            w = (int) (ih * Math.sin(DEGREE_90 - radian) + iw * Math.sin(radian));
            h = (int) (ih * Math.sin(radian) + iw * Math.sin(DEGREE_90 - radian));
        }
        BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
        Graphics g = image.getGraphics();
        Graphics2D g2d = (Graphics2D) g.create();

        // calculate the center of the icon.
        int cx = iw / 2;
        int cy = ih / 2;

        // move the graphics center point to the center of the icon.
        g2d.translate(w/2, h/2);

        // rotate the graphcis about the center point of the icon
        g2d.rotate(Math.toRadians(originalAngle));

        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        icon.paintIcon(c, g2d, -cx, -cy);

        g2d.dispose();
        return new ImageIcon(image);
    }

Notes: updated after taking Ken’s suggestion. Thanks Ken.

Information and Links

Join the fray by commenting, tracking what others have to say, or linking to it from your blog.


Other Posts
Auto-fit visible rows only
Workaround Swing Bugs

Write a Comment

Take a moment to comment and tell us what you think. Some basic HTML is allowed for formatting.

Reader Comments

Hi David,

There’s actually a much simpler way to do this. If you transform the actual graphics object, you don’t need to do all the nasty math:

public static class RotatedImageIcon implements Icon {

        private Icon fIcon;
       
        private double fRotationAngle_degress = 0;
       
        public RotatedImageIcon(Icon icon, double rotationAngle_degrees) {
            fIcon = icon;
            fRotationAngle_degress = rotationAngle_degrees;
        }
       
        public void paintIcon(Component c, Graphics g, int x, int y) {
            Graphics2D myGraphics = (Graphics2D) g.create();
           
            // calculate the center of the icon.
            int centerX = fIcon.getIconWidth()/2;
            int centerY = fIcon.getIconHeight()/2;
           
            // move the graphics center point to the center of the icon.
            myGraphics.translate(centerX, centerY);
            // rotate the graphcis about the center point of the icon
            myGraphics.rotate(Math.toRadians(fRotationAngle_degress));
           
            // request the icon paint itself with the transformed graphics at
            // its original x, y coordinate.
            fIcon.paintIcon(c, myGraphics, -centerX, -centerY);
           
            g.dispose();
        }

        public int getIconWidth() {
            return fIcon.getIconWidth();
        }

        public int getIconHeight() {
            return fIcon.getIconHeight();
        }
    }

There is a slight deficiency in my supplied code - the getWidth() and getHeight() methods need to be over-ridden with the code David used to calculate the width and height.

Good point. Your code to translate coord to center makes the code logic a lot simpler. I will change the implementation once I get a chance.

Thanks,

I updated the source code in the original post. Thanks for the suggestion, Ken!

No problem…this will be useful!

[...] an active blog to showcase the new features as they are made available. While the latest entry on rotating icons is quite useful, the previous “real” one was back in December. And on a related note, [...]