【问题标题】:Graphics2D - Antialias a Nearest-Neighbor along pixel bordersGraphics2D - Antialias 沿像素边界的最近邻
【发布时间】:2014-07-15 13:44:50
【问题描述】:

我有一个(小)BufferedImage,需要使用最近邻插值法将其放大,然后绘制到Graphics2D。图像具有 1 位 alpha 信息并使用抗锯齿和此代码进行渲染

AffineTransform oldT = g.getTransform();
Paint oldP = g.getPaint();
int w = img.getWidth(), h = img.getHeight();
g.transform(at);
g.setPaint(new TexturePaint(img, new Rectangle2D.Double(0, 0, w, h)));
g.fillRect(0, 0, w, h);
g.setPaint(oldP);
g.setTransform(oldT);

其中imgBufferedImage,使用at 作为AffineTransform 进行渲染。由

激活的抗锯齿
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

产生不错的效果,但只针对整个图像的边框;看起来很奇怪:

请注意,顶部边框实际上是图像边框,而右侧是从不透明像素到透明像素的过渡。

是否有最佳做法可以在图像中实现与应用于边框相同的抗锯齿?请注意,除 NearestNeighbor 之外的其他插值方法是不可接受的。

提前感谢任何提示。

渲染不应该花费太长时间,因为它是 paintComponent 方法的一部分,但预处理 BufferedImage 是可能的。不过,AffineTransform 是(非常)可变的。


编辑

我通过使用两步法取得了一点小进步:

AffineTransform oldT = g.getTransform();
Paint oldP = g.getPaint();
int w = img.getWidth(), h = img.getHeight(), texw = (int) (w*oldT.getScaleX()), texh = (int) (h *  oldT.getScaleY());
BufferedImage tex = new BufferedImage(texw, texh, BufferedImage.TYPE_INT_ARGB);
Graphics2D tg = tex.createGraphics();
tg.scale(oldT.getScaleX(), oldT.getScaleY());
tg.drawImage(img, 0, 0, this);
g.transform(at);
g.scale(1/oldT.getScaleX(), 1/oldT.getScaleY());
g.setPaint(new TexturePaint(tex, new Rectangle2D.Double(0, 0, texw, texh)));
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.fillRect(0, 0, texw, texh);
g.setPaint(oldP);
g.setTransform(oldT);

生成此图像:

不过,这仍然不完美。我试过VALUE_INTERPOLATION_BICUBIC,但这非常慢并且基本上产生了相同的结果。我希望有一种方法可以获得完全相同的抗锯齿效果,因为它仍然很烦人。

【问题讨论】:

  • An stackoverflow.com/help/mcve 在这里可能会有所帮助 - 特别是包含原始图像的图像,因为根据一种说法,工件似乎只出现在图像 IN 中,当它包含从完全不透明到完全透明像素的过渡时。 (解决这个问题可能有点棘手,但也许有人会尝试一下......)
  • @Marco13 这里的问题与特定图像无关,我终于找到了一个好看且执行的解决方案。如果没有人想出更好的方法,我会将其作为临时答案发布。当我有时间时,我也可能会制作一个 MCVE,但这是一个相当复杂的......

标签: java swing graphics graphics2d antialiasing


【解决方案1】:

经过大量调整和测试的相当复杂的解决方案通过将每个像素渲染为从 BufferedImage 读取其颜色和透明度的形状来提供非常好的质量:

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.image.BufferedImage;

public class VectorizedImage {
    private final BufferedImage img;

    public VectorizedImage(BufferedImage img) {
        this.img = img;
    }

    public void draw(Graphics2D g) {
        Color oldC = g.getColor();
        Composite oldCo = g.getComposite();
        AlphaComposite comp = AlphaComposite.SrcOver;
        double lap = 1/Math.sqrt(g.getTransform().getDeterminant()); // This deals with inter-pixel borders letting the background shine through
        Path2D pixel = new Path2D.Double();
        pixel.moveTo(0, 0);
        pixel.lineTo(0, 1);
        pixel.lineTo(1, 1);
        pixel.lineTo(1, 0);
        pixel.lineTo(0, 0);
        pixel.transform(AffineTransform.getScaleInstance(1+lap, 1+lap));
        for (int i = 0; i < img.getWidth(); i++)
            for (int j = 0; j < img.getHeight(); j++) {
                g.setColor(new Color(img.getRGB(i, j)));
                g.setComposite(comp.derive(img.getAlphaRaster().getSampleFloat(i, j, 0) / 255));
                g.fill(pixel.createTransformedShape(AffineTransform.getTranslateInstance(i, j)));
        }
        g.setColor(oldC);
        g.setComposite(oldCo);
    }
}

结果是这个渲染得很好的边缘:

【讨论】:

    猜你喜欢
    • 2016-05-02
    • 1970-01-01
    • 1970-01-01
    • 2020-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-31
    • 1970-01-01
    相关资源
    最近更新 更多