简体   繁体   English

如何在Java中制作圆角图像

[英]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.我使用纯Java。 How can I do that?我怎样才能做到这一点? I need a function like我需要一个像

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

架构

Edit : Added an image for information.编辑:添加了信息图像。

I suggest this method that takes an image and produces an image and keeps the image IO outside:我建议这种拍摄图像并生成图像并将图像IO保持在外面的方法:

Edit: I finally managed to make Java2D soft-clip the graphics with the help of Java 2D Trickery: Soft Clipping by Chris Campbell.编辑:我终于在 Chris Campbell 的Java 2D Trickery: Soft Clipping的帮助下成功地制作了 Java2D 软剪辑图形。 Sadly, this isn't something Java2D supports out of the box with some RenderhingHint .可悲的是,这不是 Java2D 支持的一些RenderhingHint开箱即用的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() :带有setClip()丑陋、锯齿状输出:

锯齿状固定夹

Nice, smooth output with composite trick:使用复合技巧的漂亮、流畅的输出:

平滑复合技巧

Close up of the corners on gray background ( setClip() obviously left, composite right):关闭灰色背景上的角( setClip()明显左侧,复合右侧):

灰色 bacjground 上的特写角

I am writing a follow up to Philipp Reichart 's answer.我正在写Philipp Reichart的回答的后续内容。 the answer of as an answer.作为答案的答案。

To remove the white background (seems to be black in the pictures), change g2.setComposite(AlphaComposite.SrcAtop);要去除白色背景(图片中似乎是黑色),请更改g2.setComposite(AlphaComposite.SrcAtop); to g2.setComposite(AlphaComposite.SrcIn);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);如果我使用g2.setComposite(AlphaComposite.SrcAtop); :
在此处输入图片说明

When I use g2.setComposite(AlphaComposite.SrcIn);当我使用g2.setComposite(AlphaComposite.SrcIn); the background is transparent.背景是透明的。

I found another way using TexturePaint :我找到了另一种使用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.如果您有一个非动画图像,可以通过只创建一次 BufferedImage 并为每次绘制保留它来简化此代码。

If your image is animated though you have to recreate the BufferedImage on each paint.如果您的图像是动画的,尽管您必须在每次绘制时重新创建 BufferedImage。 (Or at least i have not found a better solution for this yet.) (或者至少我还没有找到更好的解决方案。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM