From the original question (below), I am now offering a bounty for the following:
An AlphaComposite
based solution for rounded corners.
- Please demonstrate with a
JPanel
. - Corners must be completely transparent.
- Must be able to support JPG painting, but still have rounded corners
- Must not use setClip (or any clipping)
- Must have decent performance
Hopefully someone picks this up quick, it seems easy.
I will also award the bounty if there is a well-explained reason why this can never be done, that others agree with.
Here is a sample image of what I have in mind (but usingAlphaComposite
)
Original question
I've been trying to figure out a way to do rounded corners using compositing, very similar to How to make a rounded corner image in Java or http://weblogs.java.net/blog/campbell/archive/2006/07/java_2d_tricker.html.
However, my attempts without an intermediate BufferedImage don't work - the rounded destination composite apparently doesn't affect the source. I've tried different things but nothing works. Should be getting a rounded red rectangle, instead I'm getting a square one.
So, I have two questions, really:
1) Is there a way to make this work?
2) Will an intermediate image actually generate better performance?
SSCCE:
the test panel TPanel
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JLabel;
public class TPanel extends JLabel {
int w = 300;
int h = 200;
public TPanel() {
setOpaque(false);
setPreferredSize(new Dimension(w, h));
setMaximumSize(new Dimension(w, h));
setMinimumSize(new Dimension(w, h));
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
// Yellow is the clipped area.
g2d.setColor(Color.yellow);
g2d.fillRoundRect(0, 0, w, h, 20, 20);
g2d.setComposite(AlphaComposite.Src);
// Red simulates the image.
g2d.setColor(Color.red);
g2d.setComposite(AlphaComposite.SrcAtop);
g2d.fillRect(0, 0, w, h);
}
}
and its Sandbox
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JFrame;
public class Sandbox {
public static void main(String[] args) {
JFrame f = new JFrame();
f.setMinimumSize(new Dimension(800, 600));
f.setLocationRelativeTo(null);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new FlowLayout());
TPanel pnl = new TPanel();
f.getContentPane().add(pnl);
f.setVisible(true);
}
}
With respect to your performance concerns the Java 2D Trickery article contains a link to a very good explanation by Chet Haase on the usage of Intermediate Images.
I think the following excerpt from O'Reilly's Java Foundation Classes in a Nutshell could be helpful to you in order to make sense of the AlphaComposite behaviour and why intermediate images may be the necessary technique to use.
I have looked into this issue and cannot see how to do this in a single call to system classes.
Graphics2D is an abstract instance, implemented as SunGraphics2D. The source code is available at for example docjar, and so we could potentially just 'do the same, but different' by copy some code. However, methods to paint an image depends on some 'pipe' classes which are not available. Although you do stuff with classloading, you will probably hit some native, optimized class which cannot be manipulated to do the theoretically optimal approach; all you get is image painting as squares.
However we can make an approach in which our own, non-native (read:slow?), code runs as little as possible, and not depending on the image size but rather the (relatively) low area in the round rect. Also, without copying the images in memory, consuming a lot of memory. But if you have a lot of memory, then obviously, a cached image is faster after the instance has been created.
Alternative 1:
Alternative 2:
Hope this helps, this is somewhat of a second-best solution but that's life (this is when some graphics-guru comes and proves me wrong (??)..) ;-)