我想制作一个圆角的图像。图像将来自输入,我将使其圆角然后保存。我使用纯java。我怎样才能做到这一点?我需要像
这样的功能public void makeRoundedCorner(Image image, File outputFile){
.....
}
修改:添加了图片以供参考。
答案 0 :(得分:29)
我建议这种方法拍摄图像并生成图像并将图像IO保持在外面:
编辑我终于在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;
}
这是一个测试驱动程序:
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"));
}
这就是上面方法的输入/输出:
输入:
setClip()
的丑陋,参差不齐的输出:
使用复合技巧的平滑输出:
关闭灰色背景上的角落(setClip()
明显左侧,右侧合成):
答案 1 :(得分:2)
我正在撰写对 Philipp Reichart 的回答的跟进。 作为答案的答案。
要删除白色背景(图片中似乎是黑色),请更改g2.setComposite(AlphaComposite.SrcAtop);
到g2.setComposite(AlphaComposite.SrcIn);
这对我来说是个大问题,因为我有不同的透明图像,我不想丢失。
如果我使用g2.setComposite(AlphaComposite.SrcAtop);
:
当我使用g2.setComposite(AlphaComposite.SrcIn);
时,背景是透明的。
答案 2 :(得分:0)
我找到了另一种使用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);
如果您有一个非动画图像,只需创建一次BufferedImage并为每个绘画保留它,就可以简化此代码。
如果你的图像是动画的,你必须在每个颜色上重新创建BufferedImage。 (或者至少我还没有找到更好的解决方案。)