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

[macosx] Components cannot be rendered in HiDPI to BufferedImage

XMLWordPrintable

    • b12
    • os_x

        A DESCRIPTION OF THE REQUEST :
        When painting a component via component.paint(Graphics), it is impossible to paint the HiDPI version of the component (e.g. a JCheckBox) to a BufferedImage.

        Even with a double-sized BufferedImage and a 2x scale factor, components are still rendered in their low/regular resolution variant.

        JUSTIFICATION :
        Sometimes it is necessary to paint a component to a BufferedImage, e.g. to use in an animation. One would expect to be able to achieve the same quality when painting to a buffer as it is possible when painting to the screen. Currently that's not possible with a BufferedImage.

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        When painting a component to a BufferedImage with a scale factor of 2x, I would expect the HiDPI version of the component to be rendered.
        ACTUAL -
        Even with a scale factor of 2x set, components are always painted in low/regular resolution, thus look pixely.

        ---------- BEGIN SOURCE ----------
        import javax.swing.*;
        import java.awt.*;
        import java.awt.image.BufferedImage;

        // Simple demo class. I'd expect both checkboxes to render in the same quality, but they don't using a BufferedImage.
        public class RenderHiDPI {

            public static void main(String[] args) {

                final JFrame frame = new JFrame();
                final JLabel label = new JLabel();
                frame.getContentPane().setLayout(new FlowLayout());
                final JCheckBox hiDPICheckBox = new JCheckBox("Hi DPI");
                hiDPICheckBox.setFocusable(false);
                frame.getContentPane().add(hiDPICheckBox);
                frame.getContentPane().add(label);
                final JCheckBox checkBox = new JCheckBox("Lo DPI");
                checkBox.setSize(new Dimension(100, 100));
                final BufferedImage image = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
                final Graphics g = image.getGraphics();
                ((Graphics2D)g).scale(2f, 2f);
                checkBox.paint(g);
                g.dispose();
                label.setIcon(new Icon(){
                    @Override
                    public void paintIcon(final Component c, final Graphics g, final int x, final int y) {
                        final Graphics2D graphics = (Graphics2D)g.create();
                        graphics.scale(0.5f, 0.5f);
                        graphics.drawImage(image, x, y, c);
                    }

                    @Override
                    public int getIconWidth() {
                        return 100;
                    }

                    @Override
                    public int getIconHeight() {
                        return 100;
                    }
                });

                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        frame.setBounds(100, 100, 100, 100);
                        frame.setVisible(true);
                    }
                });
            }
        }
        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        Use VolatileImage (scaling not necessary)

              alexsch Alexandr Scherbatiy
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

                Created:
                Updated:
                Resolved: