java 如何在Java中制作圆角图像

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7603400/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 20:39:22  来源:igfitidea点击:

How to make a rounded corner image in Java

javaimageimage-processingborder

提问by Ali Davut

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

我想制作带有圆角的图像。图像将来自输入,我将其圆角然后保存。我使用纯Java。我怎样才能做到这一点?我需要一个像

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

Schema

架构

Edit: Added an image for information.

编辑:添加了信息图像。

回答by Philipp Reichart

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 Clippingby Chris Campbell. Sadly, this isn't something Java2D supports out of the box with some RenderhingHint.

编辑:我终于在 Chris Campbell的Java 2D Trickery: Soft Clipping的帮助下成功地制作了 Java2D 软剪辑图形。遗憾的是,这不是 Java2D 支持的一些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():

丑陋,锯齿状的输出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):

关闭灰色背景上的角落(setClip()明显左侧,复合右侧):

closeup corners on gray bacjground

灰色 bacjground 上的特写角

回答by ossobuko

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

我正在写Philipp Reichart的回答的后续内容。作为答案的答案。

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

要去除白色背景(图片中似乎是黑色),更改g2.setComposite(AlphaComposite.SrcAtop);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

如果我使用g2.setComposite(AlphaComposite.SrcAtop);
在此处输入图片说明

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

当我使用g2.setComposite(AlphaComposite.SrcIn);背景是透明的。

回答by Frederic Leitenberger

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. (Or at least i have not found a better solution for this yet.)

如果您的图像是动画的,尽管您必须在每次绘制时重新创建 BufferedImage。(或者至少我还没有找到更好的解决方案。)