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 ----------
|