Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8017626

[OGL] Translucent VolatileImages don't paint correctly

XMLWordPrintable

    • b22
    • generic
    • generic

        FULL PRODUCT VERSION :
        java version " 1.7.0_40-ea "
        Java(TM) SE Runtime Environment (build 1.7.0_40-ea-b29)
        Java HotSpot(TM) 64-Bit Server VM (build 24.0-b48, mixed mode)

        ADDITIONAL OS VERSION INFORMATION :
        Mac 10.8.3

        EXTRA RELEVANT SYSTEM CONFIGURATION :
        Graphics Card: Intel HD Graphics 3000.
        This has also happened with other Macs, regardless of Graphics Card.

        A DESCRIPTION OF THE PROBLEM :
        When drawing a translucent VolatileImage to a BufferedImage (or calling VolatileImage.getSnapshot()) and then drawing that BufferedImage to the screen graphics, the translucent pixels are rendered incorrectly. Instead of being rendered as translucent, they are rendered with a black background.

        If the VolatileImage is drawn right to the screen graphics, this problem does not occur.

        REGRESSION. Last worked in version 6u45

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        1. Create a translucent VolatileImage
        2. Clear it
        3. Fill with a half opaque color (such as rgba(255, 255, 255, 128))

        4a. Create a BufferedImage of type INT_ARGB
        4b. Draw the VolatileImage to the BufferedImage's graphics

        -- or instead of doing steps 4a and 4b, do:
        4. Create a BufferedImage by calling VolatileImage.getSnapshot()
        ---

        5. Draw the BufferedImage obtained in steps 4a/4b or 4 to the screen graphics.



        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        I expect the BufferedImage created in steps 4 or 4a/4b to look exactly as if I had created a BufferedImage and filled it with the half opaque color and then painted it to the screen graphics.

        I also expect the BufferedImage created in steps 4 or 4a/4b to look exactly like the VolatileImage when the VolatileImage is painted directly to the screen graphics.
        ACTUAL -
        The BufferedImage created in steps 4 or 4a/4b has a black tinge to it where the pixels are supposed to be translucent.

        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------

        import java.awt.AlphaComposite;
        import java.awt.BorderLayout;
        import java.awt.Color;
        import java.awt.Dimension;
        import java.awt.Graphics2D;
        import java.awt.GraphicsConfiguration;
        import java.awt.GraphicsEnvironment;
        import java.awt.GridBagConstraints;
        import java.awt.GridBagLayout;
        import java.awt.Insets;
        import java.awt.Transparency;
        import java.awt.event.ActionEvent;
        import java.awt.event.ActionListener;
        import java.awt.image.BufferedImage;
        import java.awt.image.VolatileImage;

        import javax.swing.JButton;
        import javax.swing.JFrame;
        import javax.swing.JLabel;
        import javax.swing.JPanel;
        import javax.swing.SwingUtilities;

        /**
         * Shows the difference between the painting of a translucent BufferedImage and a translucent
         * VolatileImage.
         *
         *
         * On Java 6, this works fine. On Java 7, the VolatileImages are not painted correctly, when painted
         * onto a BufferedImage prior to being painted to screen graphics.
         *
         * @author jfinley
         *
         */
        public class PaintTest {

        public PaintTest() {

        JPanel bufferedImagePanel = new JPanel() {
        protected void paintComponent(java.awt.Graphics g) {
        super.paintComponent(g);
        BufferedImage image = getBufferedImage();
        g.drawImage(image, 0, 0, null);
        };
        };

        JPanel bufferedImagePanel2 = new JPanel() {
        protected void paintComponent(java.awt.Graphics g) {
        super.paintComponent(g);
        BufferedImage bImage = getBufferedImage();

        BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = image.createGraphics();

        //not really necessary, but in there for completeness
        g2.setComposite(AlphaComposite.Clear);
        g2.setColor(new Color(255, 255, 255, 0));
        g2.fillRect(0,0, image.getWidth(), image.getHeight());

        g2.setComposite(AlphaComposite.SrcOver);
        g2.drawImage(bImage, 0, 0, null);
        g2.dispose();

        g.drawImage(image, 0, 0, null);
        };
        };

        JPanel volatileImagePanel = new JPanel() {
        protected void paintComponent(java.awt.Graphics g) {
        super.paintComponent(g);
        VolatileImage vImage = getVolatileImage();

        /**
         * If we draw the VolatileImage directly to g, it works fine... but
         * if we draw VolatileImage.getSnapshot(), or otherwise convert the VolatileImage
         * to a buffered image, we get the black halo funk of death.
         */
        g.drawImage(vImage, 0, 0, null); //works
        //g.drawImage(vImage.getSnapshot(), 0, 0, null); //black halo funk of death
        };
        };

        JPanel volatileImagePanel2 = new JPanel() {
        protected void paintComponent(java.awt.Graphics g) {
        super.paintComponent(g);
        VolatileImage vImage = getVolatileImage();

        /**
         * If we draw the VolatileImage directly to g, it works fine... but
         * if we draw VolatileImage.getSnapshot(), or otherwise convert the VolatileImage
         * to a buffered image, we get the black halo funk of death.
         */
        //g.drawImage(vImage, 0, 0, null); //works
        g.drawImage(vImage.getSnapshot(), 0, 0, null); //black halo funk of death
        };
        };

        JPanel volatileImagePanel3 = new JPanel() {
        protected void paintComponent(java.awt.Graphics g) {
        super.paintComponent(g);
        VolatileImage vImage = getVolatileImage();

        /**
         * If we draw the VolatileImage directly to g, it works fine... but
         * if we draw VolatileImage.getSnapshot(), or otherwise convert the VolatileImage
         * to a buffered image, we get the black halo funk of death.
         */
        //g.drawImage(vImage, 0, 0, null); //works
        //g.drawImage(vImage.getSnapshot(), 0, 0, null); //black halo funk of death

        BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = image.createGraphics();

        //not really necessary, but in there for completeness
        g2.setComposite(AlphaComposite.Clear);
        g2.setColor(new Color(255, 255, 255, 0));
        g2.fillRect(0,0, image.getWidth(), image.getHeight());

        g2.setComposite(AlphaComposite.SrcOver);
        g2.drawImage(vImage, 0, 0, null);
        g2.dispose();

        g.drawImage(image, 0, 0, null);
        };
        };

        final JPanel mainPanel = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints(0, 1, 1, 1, 0, 0,
        GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0);

        mainPanel.add(new JLabel( " Direct to g " ), gbc);
        gbc.gridy++;
        mainPanel.add(new JLabel( " BufferImage Proxy " ), gbc);
        gbc.gridy++;
        mainPanel.add(new JLabel( " BufferImage Proxy 2 " ), gbc);

        gbc.gridx = 1; gbc.gridy = 0;
        mainPanel.add(new JLabel( " BufferedImages " ), gbc);
        gbc.gridx++;
        mainPanel.add(new JLabel( " VolatileImages " ), gbc);

        gbc.gridx = 1; gbc.gridy = 1; gbc.weightx = 1; gbc.weighty = 1;
        mainPanel.add(bufferedImagePanel, gbc);
        gbc.gridy++;
        mainPanel.add(bufferedImagePanel2, gbc);
        gbc.gridx = 2; gbc.gridy = 1;
        mainPanel.add(volatileImagePanel, gbc);
        gbc.gridy++;
        mainPanel.add(volatileImagePanel2, gbc);
        gbc.gridy++;
        mainPanel.add(volatileImagePanel3, gbc);


        JButton repaintButton = new JButton( " Repaint " );
        repaintButton.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent e) {
        mainPanel.repaint();
        }
        });

        gbc.gridx = 1; gbc.gridy++; gbc.gridwidth = 2; gbc.weighty = 0;
        mainPanel.add(repaintButton, gbc);


        JFrame mainFrame = new JFrame( " O.M.G. " );
        mainFrame.getContentPane().setLayout(new BorderLayout());
        mainFrame.getContentPane().add(mainPanel, BorderLayout.CENTER);
        mainFrame.setPreferredSize(new Dimension(400, 400));
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.pack();
        mainFrame.setVisible(true);

        }

        private BufferedImage getBufferedImage() {
        BufferedImage image = new BufferedImage(100, 100, BufferedImage.TRANSLUCENT);
        Graphics2D g = image.createGraphics();

        //not really necessary, in here for completeness
        g.setComposite(AlphaComposite.Clear);
        g.setColor(new Color(255, 255, 255, 0));
        g.fillRect(0,0, image.getWidth(), image.getHeight());

        g.setComposite(AlphaComposite.SrcOver);
        g.setColor(new Color(255, 0, 0, 128));
        g.fillRect(10, 10, image.getWidth()-20, image.getHeight()-20);

        g.dispose();
        return image;
        }

        private VolatileImage getVolatileImage() {
        GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
        VolatileImage vImage = gc.createCompatibleVolatileImage(100, 100, Transparency.TRANSLUCENT);
        Graphics2D g = vImage.createGraphics();

        //necessary, as VolatileImages start out filled opaque white
        g.setComposite(AlphaComposite.Clear);
        g.setColor(new Color(255, 255, 255, 0));
        g.fillRect(0,0, vImage.getWidth(), vImage.getHeight());

        g.setComposite(AlphaComposite.SrcOver);
        g.setColor(new Color(255, 0, 0, 128));
        g.fillRect(10, 10, vImage.getWidth()-20, vImage.getHeight()-20);

        g.dispose();
        return vImage;
        }

        public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable(){
        public void run() {
        new PaintTest();
        }
        });
        }
        }
        ---------- END SOURCE ----------

              serb Sergey Bylokhov
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

                Created:
                Updated:
                Resolved: