2
votes

I've been working on a program that involves the rotation of a partially transparent image over a transparent form. The drawing of the image originally worked fine, I also set my custom panel's background color to a transparent light blue this worked fine as well. My problems started when I tried rotating my image.

In order to rotate it I had to convert the panel.getGraphics() over to a Graphics2D. When I did this the transparency went away, So I finished up on my rotation code and then read up on transparency. I found that I could set the composite of the Graphics2D and that is exactly what I did as seen here:

@Override
public void paintComponent(Graphics g) 
{
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D)g;

    g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC));
    g2d.setColor(new Color(0, 0, 200, 90));
    g2d.fillRect(0, 0, this.getWidth(), this.getHeight());
    g2d.rotate(radians);
    g2d.drawImage(img, 0, 0, null);

    repaint();
}

When I run this I get the form as follows (Please note that this is not my normal image):

Before Rotation

This is almost what I want except for it doesn't show the transparent blue background. However if I rotate the image the blue shows:

After Rotation

2
well, for better help sooner post an SSCCE, short, runnable, compilable, otherwise this question isn't answerable,mKorbel
1- Don't use panel.getGraphics. 2- make sure that you've set the panel to transparent (setOpaque(false)), remember that you become responsible for now filling the background of the component in your translucent blue colorMadProgrammer
Don't ever call repaint() in paintComponent(). This is creating an infinite loop!Guillaume Polet
Thanks so much simply setting the setOpaque method to false fixed it! =)Lost_Soul
@Lost_Soul Trust me, you should never do that. This means that you have an issue somewhere else. You should call repaint() when you change the value of radians or any other attribute that will modify the current display. Invoking repaint() inside paintComponent() means that your application is continuously painting which will make your application slow, unresponsive and eat up your CPU.Guillaume Polet

2 Answers

2
votes

Problem is partially in the composite you specify: AlphaComposite.SRC
I don't really know what for did you use it but it overwrites source pixels data. That is why panel background gets overwrited when image is painted over it.

I suggest you to read about composite in graphics if you didn't read it yet: http://docs.oracle.com/javase/tutorial/2d/advanced/compositing.html

Anyway, see the example how something similar could be done:
(this is just one of possibilities - you could do it in ten other ways)

public class SmileyTest
{
    private static Color bg = new Color ( 0, 0, 255, 128 );
    private static float angle = 0f;

    public static void main ( String[] args )
    {
        final ImageIcon icon = new ImageIcon ( SmileyTest.class.getResource ( "icons/smiley.png" ) );

        JDialog frame = new JDialog ();
        frame.setLayout ( new BorderLayout () );

        // We should not use default background and opaque panel - that might cause repaint problems
        // This is why we use JPanel with transparent background painted and opacity set to false
        JPanel transparentPanel = new JPanel ( new BorderLayout () )
        {
            protected void paintComponent ( Graphics g )
            {
                super.paintComponent ( g );
                g.setColor ( bg );
                g.fillRect ( 0, 0, getWidth (), getHeight () );
            }
        };
        transparentPanel.setOpaque ( false );
        frame.add ( transparentPanel );

        // Image in another component
        final JComponent component = new JComponent ()
        {
            protected void paintComponent ( Graphics g )
            {
                super.paintComponent ( g );

                Graphics2D g2d = ( Graphics2D ) g;

                // For better image quality when it is rotated
                g2d.setRenderingHint ( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR );

                // Rotating area using image middle as rotation center
                g2d.rotate ( angle * Math.PI / 180, getWidth () / 2, getHeight () / 2 );

                // Transparency for image
                g2d.setComposite ( AlphaComposite.getInstance ( AlphaComposite.SRC_OVER, 0.5f ) );

                // Draing image
                g2d.drawImage ( icon.getImage (), 0, 0, null );
            }
        };
        transparentPanel.add ( component );

        // Rotation animation (24 frames per second)
        new Timer ( 1000 / 48, new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                angle += 0.5f;
                component.repaint ();
            }
        } ).start ();

        frame.setUndecorated ( true );
        AWTUtilities.setWindowOpaque ( frame, false );
        frame.setSize ( icon.getIconWidth (), icon.getIconHeight () );
        frame.setLocationRelativeTo ( null );
        frame.setVisible ( true );
    }
}

Just run this and see the result: enter image description here

There are also a few comments over the code why you should or shouldn't do something.
Make sure you read them carefully.

0
votes

Yet another way to do it:

import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class TestTransparentRotatedImage {

    private static class TransparentRotatedImage extends JPanel {
        private final Image image;
        private double rotation;

        public TransparentRotatedImage(Image image) {
            this.image = image;
            setOpaque(false);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g;
            g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
            g2.setColor(new Color(0, 0, 200, 90));
            g2.fillRect(0, 0, getWidth(), getHeight());
            g2.setTransform(getTransformation());
            g2.drawImage(image, 0, 0, this);
        }

        protected AffineTransform getTransformation() {
            try {
                AffineTransform translateInstance = AffineTransform.getTranslateInstance(+image.getWidth(this) / 2,
                        +image.getWidth(this) / 2);
                AffineTransform inverse = translateInstance.createInverse();
                AffineTransform rotateInstance = AffineTransform.getRotateInstance(Math.toRadians(rotation));
                AffineTransform at = translateInstance;
                at.concatenate(rotateInstance);
                at.concatenate(inverse);
                return at;
            } catch (NoninvertibleTransformException e) {
                e.printStackTrace();
                return null;
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(image.getWidth(this), image.getHeight(this));
        }

        public void setRotation(double rotation) {
            this.rotation = rotation;
            repaint();
        }
    }

    protected void initUI() throws MalformedURLException {
        final JFrame frame = new JFrame(TestTransparentRotatedImage.class.getSimpleName());
        frame.setUndecorated(true);
        frame.setBackground(new Color(0, 0, 0, 0));
        frame.getContentPane().setBackground(new Color(0, 0, 0, 0));
        // com.sun.awt.AWTUtilities.setWindowOpacity(frame, 0);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        final TransparentRotatedImage rotatedImage = new TransparentRotatedImage(new ImageIcon(new URL(
                "http://files.myopera.com/supergreatChandu8/albums/5466862/smiley-transparent.png")).getImage());
        frame.add(rotatedImage);
        final JSlider slider1 = new JSlider(0, 360);
        slider1.setValue(0);
        slider1.addChangeListener(new ChangeListener() {

            @Override
            public void stateChanged(ChangeEvent e) {
                rotatedImage.setRotation(slider1.getValue());
            }
        });
        frame.add(slider1, BorderLayout.SOUTH);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
            UnsupportedLookAndFeelException {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                try {
                    new TestTransparentRotatedImage().initUI();
                } catch (MalformedURLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
    }
}

enter image description here