How to make a rounded corner image in Java

I want to make a image with rounded corners. A image will come from input and I will make it rounded corner then save it. I use pure java. How can I do that? I need a function like

public void makeRoundedCorner(Image image, File outputFile){
.....
}

Edit : Added an image for information.

Answers


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:

Ugly, jagged output with setClip():

Nice, smooth output with composite trick:

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


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:

If I use g2.setComposite(AlphaComposite.SrcAtop);:

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


I found another way using TexturePaint:

                ImageObserver obs = ...;
                int w = img.getWidth(obs);
                int h = img.getHeight(obs);

                // any shape can be used
                Shape clipShape = new RoundRectangle2D.Double(0, 0, w, h, 20, 20);

                // create a BufferedImage with transparency
                BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
                Graphics2D bg = bi.createGraphics();

                // make BufferedImage fully transparent
                bg.setComposite(AlphaComposite.Clear);
                bg.fillRect(0, 0, w, h);
                bg.setComposite(AlphaComposite.SrcOver);

                // copy/paint the actual image into the BufferedImage
                bg.drawImage(img, 0, 0, w, h, obs);

                // set the image to be used as TexturePaint on the target Graphics
                g.setPaint(new TexturePaint(bi, new Rectangle2D.Float(0, 0, w, h)));

                // activate AntiAliasing
                g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

                // translate the origin to where you want to paint the image
                g.translate(x, y);

                // draw the Image
                g.fill(clipShape);

                // reset paint
                g.setPaint(null);

This code can be simplified if you have a non-animated image, by creating the BufferedImage only once and keeping it for each paint.

If your image is animated though you have to recreate the BufferedImage on each paint. (Or at least i have not found a better solution for this yet.)


Need Your Help

Best way to share database connection param with mongoose/node.js

node.js mongodb express mongoose

I'm using Mongoose to manage a Mongo database. My connection file is quite simple: