0%

解决Graphics2D生成的图像锯齿问题

问题描述

后台有两个业务:生成二维码、生成群聊头像,这两个使用的方法都是利用 Graphics2D 对图片进行裁剪拼接。最近测试发现,通过这个方法生成的图片锯齿问题很严重,在 App 端即便展示的是小图也能很明显的看出。为了方便展示,下面展示的图片是放大后的,如下:
圆形群聊Logo
圆形二维码

这个情况只有圆形图片才会出现,方形图片不存在这个问题。作为对比,下面放上方形图片的展示效果:
方形群聊Logo
方形二维码

优化记录

只有生成的圆形图片存在锯齿问题,那么首先定位到问题是由裁剪图片相关的代码引起的,因此下面对这一块的代码进行优化:

  1. 首先尝试了为生成的圆形图片增加抗锯齿的配置,但是没有任何效果。

    1
    2
    // 增加抗锯齿配置
    graph.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    RenderingHints 的作用见文档:Class RenderingHints

  2. 接着继续搜寻解决方案,在 JAVA 将图片剪裁成圆形,并在圆形外带有白边 中找到了相应的优化办法:图片裁剪成圆形后,在图片外面再绘制一层圆形边界。如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 绘制圆形图片
    BufferedImage bi2 = new BufferedImage(bi1.getWidth(), bi1.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
    Graphics2D g2 = bi2.createGraphics();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    Ellipse2D.Double shape = new Ellipse2D.Double(0, 0, bi1.getWidth(), bi1.getHeight());
    g2.setClip(shape);
    g2.drawImage(bi1, 0, 0, bi1.getWidth(), bi1.getHeight(), null);
    g2.dispose();
    // 利用画笔在切割后的圆外面再画一个圆,这样画的圆不会有锯齿
    g2 = bi2.createGraphics();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    Stroke s = new BasicStroke(2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
    g2.setStroke(s);
    g2.setColor(new Color(231, 231, 231));
    g2.drawOval(0, 0, bi1.getWidth(), bi1.getHeight());
    g2.dispose();

原理就是通过绘制一个边界来消除圆形的锯齿问题:
样例图

最终优化后的效果如下:( 注:左边是优化前的,右边是优化后的 )
对比图

参考文档

JAVA 将图片剪裁成圆形,并在圆形外带有白边
RenderingHints 中文文档