Java Graphics2D-沿像素边界的最近邻
我有一个(小的)Java Graphics2D-沿像素边界的最近邻,java,swing,graphics,graphics2d,antialiasing,Java,Swing,Graphics,Graphics2d,Antialiasing,我有一个(小的)buffereImage,它需要使用最近邻插值进行放大,然后绘制成图形2d。该图像具有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
buffereImage
,它需要使用最近邻插值进行放大,然后绘制成图形2d
。该图像具有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);
其中,img
是使用at
作为仿射变换进行渲染的buffereImage
。由激活的抗锯齿
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
产生良好的效果,但仅适用于整个图像的边界;看起来很奇怪:
请注意,顶部边框实际上是图像边框,而右侧是从不透明到透明像素的过渡
是否有最佳实践可以在图像中实现与应用于边框相同的抗锯齿效果?请注意,除了最近邻点以外的其他插值方法是不可接受的
提前感谢您的任何提示
渲染不应该花费太长时间,因为它是paintComponent
方法的一部分,但是可以对buffereImage
进行预处理。不过,仿射变换是(非常)可变的
编辑
我通过使用两步方法实现了一个小的改进:
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\u INTERPOLATION\u BICUBIC
,但是速度非常慢,基本上产生了相同的结果。我希望有一种方法可以获得完全相同的抗锯齿效果,因为它仍然令人恼火。一个相当复杂的解决方案,通过大量调整和测试,将每个像素渲染为一个形状,从缓冲图像读取其颜色和透明度,从而提供了非常好的质量:
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);
}
}
导入java.awt.AlphaComposite;
导入java.awt.Color;
导入java.awt.Composite;
导入java.awt.Graphics2D;
导入java.awt.geom.AffineTransform;
导入java.awt.geom.Path2D;
导入java.awt.image.buffereImage;
公共类矢量化图像{
专用最终缓冲图像img;
公共矢量图像(BuffereImage img){
this.img=img;
}
公共作废图纸(图形2D g){
颜色oldC=g.getColor();
复合oldCo=g.getComposite();
AlphaComposite comp=AlphaComposite.SrcOver;
double lap=1/Math.sqrt(g.getTransform().getDeterminate());//这涉及像素间的边界,让背景通过
Path2D像素=新的Path2D.Double();
像素。移动到(0,0);
像素.lineTo(0,1);
像素.lineTo(1,1);
像素.lineTo(1,0);
像素.lineTo(0,0);
变换(仿射变换.getScaleInstance(1+lap,1+lap));
对于(int i=0;i
结果是这条渲染得很好的边:
An在这里可能会有所帮助,尤其是包括原始图像的图像,因为根据一种说法,当图像包含从完全不透明到完全透明的像素过渡时,伪影似乎只出现在图像中。(解决这个问题可能有点棘手,但也许有人会尝试一下…@Marco13这里的问题与特定的图像无关,我终于找到了一个美观且性能良好的解决方案。如果没有人能想出更好的办法,我会把这个作为一个临时的回答。当我有时间的时候,我也可以做一个MCVE,但这是一个相当复杂的一个。。。