开发者

How to make a rounded corner image in Java

开发者 https://www.devze.com 2023-04-09 04:45 出处:网络
I wa开发者_如何学Pythonnt 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

I wa开发者_如何学Pythonnt 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){
.....
}

How to make a rounded corner image in Java

Edit : Added an image for information.


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:

How to make a rounded corner image in Java

Ugly, jagged output with setClip():

How to make a rounded corner image in Java

Nice, smooth output with composite trick:

How to make a rounded corner image in Java

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

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:

How to make a rounded corner image in Java

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

How to make a rounded corner image in Java

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.)

0

精彩评论

暂无评论...
验证码 换一张
取 消