在BufferedImage上绘制带有不透明度的圆角矩形

我一直在试图为我正在开发的一款小游戏实现基本的文本泡泡。 不想过于花哨,我从一个基本的圆角矩形开始,边框包含一些文本:

然后,我决定文本泡泡应该在预设时间后淡出。 这就是我偶然发现的一个问题:当我试图在测试窗口中显示气泡时,一切运行良好,但是当我将它们展示在游戏中时,泡泡消失时出现了扭曲。 我测试了一些,调试了一下,发现两种情况之间唯一的区别是在测试窗口中我用paintComponent方法的Graphics画了泡泡,而在游戏中我使用BufferedImages来模拟图层并使用image.createGraphics中的图形。 然后,我可以成功复制该错误:
显示错误的Gif

在这里,你会发现当左边的气泡渐渐消失时,与之前的渐变相比,它的圆角会改变形状,而右侧圆角上的气泡不会改变。 事实上,左侧的气泡是在BufferedImage上绘制的,然后在面板上绘制,而右侧的气泡直接绘制在面板上。
我已经隔离了重现问题所需的代码:

public static void main(String[] args) {

    JFrame frame = new JFrame("Test");
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.setLocationRelativeTo(null);
    frame.setSize(400, 400);

    JPanel panel = new JPanel() {

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            BufferedImage image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
            Graphics graphics = image.createGraphics();

            paintExampleBubble(graphics, 50, 50);

            g.drawImage(image, 0, 0, this);

            paintExampleBubble(g, 250, 50);
        }
    };

    frame.getContentPane().add(panel);
    frame.setVisible(true);
}

private static final Color background = new Color(1f, 1f, 1f, 0.5f);
private static final Color foreground = new Color(0f, 0f, 0f, 0.5f);
private static final int borderRadius = 16;
private static final int width = 100;
private static final int height = 50;

private static void paintExampleBubble(Graphics g, int x, int y) {

    g.setColor(background);
    g.fillRoundRect(x, y, width, height, borderRadius, borderRadius);
    g.setColor(foreground);
    g.drawRoundRect(x, y, width, height, borderRadius, borderRadius);
}

这是上面的代码产生的结果:

无论如何,这表明绘制到BufferedImage是导致问题的原因,但暂时不能放弃BufferedImages。

我试图调试代码以查看可能会导致这种差异的原因,并且只能注意到当涉及透明度时图形对象使用不同的组件绘制,但是这并不能帮助我解决我的问题,即使可以强制图形做我想做的事情,如果可能,我宁愿避免黑客行为。

有谁知道解决这个问题的一个相对简单而有效的方法,还是解决它?

无论如何,感谢您花时间阅读此:)

PS:因为这是我第一次提出问题,所以我可能错过了一些东西,所以请随时告诉我是否属实! 这将非常感激。

编辑:正如我在评论中所说,游戏是基于像素艺术的,因此我宁愿不使用抗锯齿,但保留圆角矩形的基本像素化外观。


在这里,你会发现当左边的气泡渐渐消失时,与之前的渐变相比,它的圆角会改变形状,而右侧圆角上的气泡不会改变。 事实上,左侧的气泡是在BufferedImage上绘制的,然后在面板上绘制,而右侧的气泡直接绘制在面板上。

而不是每次使用不同的alpha值重新绘制图像,请创建一次,然后使用AlphaComposite来管理透明度。

下面是你的例子中有三个“气泡”的改编:每当改变前景色时,左边最左边的是绘制图像,右边的两个使用AlphaComposite (中间使用一次创建的图像,最右边使用JPanel图形直接使用)。

public class Test {

    public static void main(String[] args) {

        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setSize(600, 200);
        final BufferedImage image = new BufferedImage(600, 200, BufferedImage.TYPE_INT_ARGB);
        Graphics2D graphics = image.createGraphics();
        paintExampleBubble(graphics, 250, 50, foreground);
        graphics.dispose();
        final JPanel panel = new JPanel() {

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

                final BufferedImage i2 = new BufferedImage(600, 200, BufferedImage.TYPE_INT_ARGB);
                Graphics2D graphics = i2.createGraphics();
                paintExampleBubble(graphics, 50, 50, alphaForeground);
                graphics.dispose();
                g.drawImage(i2, 0, 0, this);
                //use Alpha Composite for transparency
                Composite comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER , alpha );
                g2d.setComposite(comp);
                g2d.drawImage(image, 0, 0, this);

                paintExampleBubble(g2d, 450, 50, foreground);
            }
        };
        javax.swing.Timer timer = new javax.swing.Timer(100, new ActionListener(){

            @Override
            public void actionPerformed(ActionEvent e) {
                alpha -= 0.05;

                if ( alpha < 0 ){
                    alpha = 1.0f;
                }
                alphaForeground = new Color(0f, 0f, 0f, alpha);
                panel.repaint();
            }

        });
        timer.start();
        frame.getContentPane().add(panel);
        frame.setVisible(true);
    }

    private static float alpha = 1.0f;
    private static final Color background = new Color(1f, 1f, 1f, 1f);
    private static final Color foreground = new Color(0f, 0f, 0f, 1f);
    private static Color alphaForeground = new Color(0f, 0f, 0f, alpha);
    private static final int borderRadius = 16;
    private static final int width = 100;
    private static final int height = 50;

    private static void paintExampleBubble(Graphics g, int x, int y, Color color) {
        g.setColor(background);
        g.fillRoundRect(x, y, width, height, borderRadius, borderRadius);
        g.setColor(color);
        g.drawRoundRect(x, y, width, height, borderRadius, borderRadius);
    }
}

在我的系统上,我看到最左边的变形(使用foretground颜色管理透明度),但没有使用AlphaComposite透明度

链接地址: http://www.djcxy.com/p/35449.html

上一篇: Drawing a rounded rectangle with opacity on a BufferedImage

下一篇: Convert JSON Object array into associative array