How to make a rounded corner image in Java

I am writing a follow up to Philipp Reichart's answer. the answer of as an answer.

To remove the white background (seems to be black in the pictures), change g2.setComposite(AlphaComposite.SrcAtop); to g2.setComposite(AlphaComposite.SrcIn);

This was a big problem for me because I have different images with transparency that I don't want to lose.

My original image:
enter image description here

If I use g2.setComposite(AlphaComposite.SrcAtop);:
enter image description here

When I use g2.setComposite(AlphaComposite.SrcIn); the background is transparent.


I suggest this method that takes an image and produces an image and keeps the image IO outside:

Edit: I finally managed to make Java2D soft-clip the graphics with the help of Java 2D Trickery: Soft Clipping by Chris Campbell. Sadly, this isn't something Java2D supports out of the box with some RenderhingHint.

public static BufferedImage makeRoundedCorner(BufferedImage image, int cornerRadius) {
    int w = image.getWidth();
    int h = image.getHeight();
    BufferedImage output = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);

    Graphics2D g2 = output.createGraphics();
    
    // This is what we want, but it only does hard-clipping, i.e. aliasing
    // g2.setClip(new RoundRectangle2D ...)

    // so instead fake soft-clipping by first drawing the desired clip shape
    // in fully opaque white with antialiasing enabled...
    g2.setComposite(AlphaComposite.Src);
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setColor(Color.WHITE);
    g2.fill(new RoundRectangle2D.Float(0, 0, w, h, cornerRadius, cornerRadius));
    
    // ... then compositing the image on top,
    // using the white shape from above as alpha source
    g2.setComposite(AlphaComposite.SrcAtop);
    g2.drawImage(image, 0, 0, null);
    
    g2.dispose();
    
    return output;
}

Here's a test driver:

public static void main(String[] args) throws IOException {
    BufferedImage icon = ImageIO.read(new File("icon.png"));
    BufferedImage rounded = makeRoundedCorner(icon, 20);
    ImageIO.write(rounded, "png", new File("icon.rounded.png"));
}

This it what the input/output of the above method looks like:

Input:

input image

Ugly, jagged output with setClip():

jagged with setclip

Nice, smooth output with composite trick:

smooth with composite trick

Close up of the corners on gray background (setClip() obviously left, composite right):

closeup corners on gray bacjground