【问题标题】:How to make a rounded corner image in Java如何在Java中制作圆角图像
【发布时间】:2011-11-28 00:55:48
【问题描述】:

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

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

编辑:添加图片以供参考。

【问题讨论】:

  • 您需要更具体地了解圆角:透明还是填充背景色(第一个可能会强制 PNG 作为输出格式)?固定或可变半径,如果后者相对于什么?
  • 我猜这里已经回答了:stackoverflow.com/questions/1826665/…
  • 这个问题缺少很多必要的细节,因此很难回答。
  • 一个粗略的想法围绕着new BufferedImagegetGraphics()setClip(new RoundedRectangle.Float(...)) 和对drawImage() 的调用。
  • 你误解了setClip(),让我写了一个实际的答案,见下文:)

标签: java image image-processing border


【解决方案1】:

我建议这种获取图像并生成图像并将图像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() 显然是左,复合右):

【讨论】:

  • 不过,拐角是有别名的,没有明显的RenderingHint 能满足我的要求……如果我能找到制作平滑拐角的方法,我会更新我的代码。
  • 你必须创建四个 Lines 和 Circles 并把它们放在一起,放在这里 EmptyBorders 和角落内的空间重新计算每个像素并删除它,但是为什么要重新发明这个地方有官方 API
  • @mKorbel 为什么要使用 Swing 来完成一个简单的 Java2D 任务?即使这样可以解决混叠问题,恕我直言,这将是矫枉过正。上面的代码确实有效,减去了别名的样式点。
  • Java2D 也可以在无头环境中工作,但 Swing 不是那么多(尽管这不是 OP 的要求)
  • 它有效,谢谢。我现在可以使用你的答案,但我需要平滑的角落。如果你找到方法,你添加。谢谢 Philipp Reichart。
【解决方案2】:

我正在写一个跟进 Philipp Reichart 的回答。 作为答案的答案。

要去除白色背景(在图片中似乎是黑色),更改g2.setComposite(AlphaComposite.SrcAtop);g2.setComposite(AlphaComposite.SrcIn);

这对我来说是个大问题,因为我不想丢失不同的透明图像。

我的原图:

如果我使用g2.setComposite(AlphaComposite.SrcAtop);:

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

【讨论】:

    【解决方案3】:

    我找到了另一种使用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。 (或者至少我还没有找到更好的解决方案。)

    【讨论】:

      猜你喜欢
      • 2019-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-06
      相关资源
      最近更新 更多