2014年4月10日

Java2D旋转图片边缘锯齿问题

在使用Java2D旋转图片时,如果旋转的角度不是45度的倍数,图片边缘会产生非常明显的锯齿。

旋转的代码如下:

public static BufferedImage rotate(BufferedImage image, double angle) {
    double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle));
    int w = image.getWidth(), h = image.getHeight();
    int neww = (int) Math.floor(w * cos + h * sin), newh = (int) Math.floor(h * cos + w * sin);
    BufferedImage result = new BufferedImage(neww, newh, BufferedImage.TYPE_INT_ARGB_PRE); 
    Graphics2D g = result.createGraphics();
    g.addRenderingHints(RENDER_HINT);
    g.translate((neww - w) / 2, (newh - h) / 2);
    g.rotate(angle, w / 2, h / 2);
    g.drawRenderedImage(image, null);
    g.dispose();
    return result;
}

其中已经加上了相应的RenderingHints:

private static HashMap<Object, Object> RENDER_HINT = new HashMap<Object, Object>();
static{
    RENDER_HINT.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
    RENDER_HINT.put(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
    RENDER_HINT.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
    RENDER_HINT.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    RENDER_HINT.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
}

现在对下面这张图片旋转-10度

BufferedImage logo = ImageIO.read(new File("logo.png"));
BufferedImage rotated = rotate(logo, Math.toRadians(-10));

旋转后的图片如下,图片边缘的锯齿惨不忍睹

这里有个取巧的方法可以产生出效果比较好的图片,那就是在旋转前先处理一下图片,给图片加上1-3个像素的透明边框:

public static BufferedImage prerotate(BufferedImage image) {
    BufferedImage temp =
            new BufferedImage(image.getWidth() + 2, image.getHeight() + 2,
                    BufferedImage.TYPE_INT_ARGB_PRE);
    Graphics2D g = temp.createGraphics();
    g.addRenderingHints(RENDER_HINT);
    g.drawImage(image, 1, 1, null);
    g.dispose();
    return temp;
}

先调用一下prerotaterotate,产生的图片效果就好很多了: