Как сделать закругленный угол изображения на Java - PullRequest
17 голосов
/ 30 сентября 2011

Я хочу сделать изображение с закругленными углами. Изображение будет получено из ввода, и я сделаю его закругленным углом, а затем сохраню его. Я использую чистую Java. Как я могу это сделать? Мне нужна функция типа

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

Schema

Редактировать : Добавлено изображение для информации.

Ответы [ 3 ]

29 голосов
/ 30 сентября 2011

Я предлагаю этот метод, который берет изображение, создает изображение и сохраняет внешний вид изображения вне:

Редактировать: Мне наконец-то удалось сделать софт-клип Java2D для графики с помощью Java 2D Trickery: Soft Clipping Криса Кэмпбелла. К сожалению, это не то, что 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"));
}

Вот как выглядит ввод / вывод описанного выше метода:

Введите:

input image

Гадкий, неровный вывод с setClip():

jagged with setclip

Хороший, плавный вывод с комбинированным трюком:

smooth with composite trick

Крупный план углов на сером фоне (setClip() явно слева, составной справа):

closeup corners on gray bacjground

2 голосов
/ 07 октября 2015

Я пишу продолжение до ответа Филиппа Рейхарта . ответ как ответ.

Чтобы удалить белый фон (на снимках он кажется черным), измените g2.setComposite(AlphaComposite.SrcAtop); до g2.setComposite(AlphaComposite.SrcIn);

Это было большой проблемой для меня, потому что у меня есть разные изображения с прозрачностью, которые я не хочу потерять.

Мое оригинальное изображение:
enter image description here

Если я использую g2.setComposite(AlphaComposite.SrcAtop);:
enter image description here

Когда я использую g2.setComposite(AlphaComposite.SrcIn); фон прозрачен.

0 голосов
/ 10 октября 2014

Я нашел другой способ, используя 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 на каждой краске.(Или, по крайней мере, я еще не нашел лучшего решения для этого.)

...