在JAVA中对多边形进行抗锯齿时,会出现重影白线
我正在尝试编写一个程序来绘制多边形并用所需的颜色填充它们。这是一个简单的绘画应用程序,但我面临的问题是当我绘制多边形并绘制它们时,多边形之间会出现一条细细的白线。但是当我没有对多边形进行反锯齿时,白线消失了,但是多边形并不平滑。真正的问题是,我需要使多边形平滑,同时也需要删除白色细线 绘制多边形的类是:在JAVA中对多边形进行抗锯齿时,会出现重影白线,java,paint,graphics2d,antialiasing,clipping,Java,Paint,Graphics2d,Antialiasing,Clipping,我正在尝试编写一个程序来绘制多边形并用所需的颜色填充它们。这是一个简单的绘画应用程序,但我面临的问题是当我绘制多边形并绘制它们时,多边形之间会出现一条细细的白线。但是当我没有对多边形进行反锯齿时,白线消失了,但是多边形并不平滑。真正的问题是,我需要使多边形平滑,同时也需要删除白色细线 绘制多边形的类是: public class GrayScaleManager{ private final VisualizerController controller; private f
public class GrayScaleManager{
private final VisualizerController controller;
private final BufferedImage grayScaledImage;
private final HashMap<ToolsModel, BufferedImage> grayScaleportionList;
public GrayScaleManager(VisualizerController drawingCanvas) {
this.controller = drawingCanvas;
grayScaleportionList = new HashMap<>();
grayScaledImage = toGray(Utility.bufferedImageDeepCopy(Util.getImg()));
}
public void grayScaleSelectedPortion(Graphics2D g, ToolsModel selectedArea) {
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setClip((Shape) selectedArea);
g.drawImage(grayScaledImage, 0, 0, null);
g.setClip(null);
}
private BufferedImage toGray(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
Color c = new Color(image.getRGB(j, i));
int red = (int) (c.getRed() * 0.3);
int green = (int) (c.getGreen() * 0.59);
int blue = (int) (c.getBlue() * 0.11);
int sum = red + green + blue;
Color newColor = new Color(sum, sum, sum);
image.setRGB(j, i, newColor.getRGB());
}
}
return image;
}
public VisualizerController getController() {
return controller;
}
public HashMap<ToolsModel, BufferedImage> getGrayScaleportionList() {
return grayScaleportionList;
}
}
优点:
1.如果使用相同的颜色绘制多个图层,则这些图层看起来就像是一个单独的图层(单层)。
2.没有鬼白线。
欺骗:
1.线条的边缘不平滑
场景2:如果应用了渲染,只需在metod中应用下面的代码即可
public void grayScaleSelectedPotion(Graphics2D g, ToolsModel selectedArea){
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setClip((Shape) selectedArea);
g.drawImage(grayScaledImage, 0, 0, null);
g.setClip(null);
}
优点:
1.单层。
2.边缘光滑。
欺骗:
1.出现鬼影白线
场景3:如果已渲染但drawImage()已删除
优点:
1.边缘光滑。
2.没有鬼白线
缺点:
1.即使层具有相同的颜色,也可以清楚地看到多个层(这是不可接受的)
总之,三种情况下的所有三个缺点都应该消除
从@MadProgrammer实现解决方案后,代码如下所示:
super.paintComponent(g);
grayImage = grayScaleManager.getGrayImage();
BufferedImage mask = new BufferedImage(img.getWidth(),img.getHeight(),BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = mask.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
shadeList.forEach((shape)->{
g2d.setColor(shape.getColor());
if (shape.getColor().getAlpha() != NULL_ALPHA) {
//g2d.fill((Shape)shape);
}
g2d.fill((Shape)shape);
if (shape.getColor().getAlpha() == SELECTION_ALPHA) {
g2d.setStroke(new BasicStroke(1));
g2d.setColor(Color.red.brighter().brighter().brighter());
g2d.draw((Shape) shape);
}
});
// g2d.dispose();
masked = applyMask(mask,grayImage,AlphaComposite.SRC_IN);
g.drawImage(img,0,0,null);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, 0.0f));
g.drawImage(masked, 0, 0, this);
g2d.dispose();
g.dispose();
}
/*Added methods for the changes applymask method*/
public static BufferedImage applyMask(BufferedImage sourceImage, BufferedImage maskImage, int method) {
System.out.println("I am in applymask");
BufferedImage maskedImage = null;
if (sourceImage != null) {
System.out.println("I am in applymask in if case");
int width = maskImage.getWidth(null);
int height = maskImage.getHeight(null);
maskedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D mg = maskedImage.createGraphics();
int x = (width - sourceImage.getWidth(null)) / 2;
int y = (height - sourceImage.getHeight(null)) / 2;
//mg.setColor(Color.RED);
//mg.drawImage(sourceImage, x, y, null);
mg.drawImage(sourceImage, 0, 0, null);
mg.setComposite(AlphaComposite.getInstance(method,0.0f));
mg.dispose();
}
return maskedImage;
}
但是现在灰度图像没有绘制,多边形重叠,当添加灰度图像时,我们无法向多边形添加其他颜色。我猜您的图像显示您的代码在2D中构建多边形,这就是为什么这显示了一条白线,让人感觉一个多边形与其他多边形重叠。您可以通过Area类创建单个剪裁形状的并集,然后将其应用为灰度图像剪裁遮罩来解决问题。好的,这看起来有点复杂,但这会让你更接近你的目标。基本上,
setClip
不会生成“软边”,你必须作弊
其基本思想是生成要捕获区域的透明图像,这将成为“遮罩”。然后,我们使用遮罩“剪切”源图像的一部分,最后将其应用于原始图像
这与以下示例中演示的基本概念相同
// The master image or background
master = ImageIO.read(...);
// Generate a gray scaled version of the master image
// This is what we will be cutting out
ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
grayScaled = op.filter(master, null);
int width = master.getWidth() / 4;
int height = master.getHeight() / 4;
// This simply what I'm using as the base "selection"
// But for all intents purpose, it can be anything which can
// be painted through Graphics
Shape shape = new Rectangle2D.Double(0, 0, width, height);
// The base mask, not that it's transparent
BufferedImage mask = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = mask.createGraphics();
// Offset the location to apply the "selection"
g2d.translate((master.getWidth() - shape.getBounds().width) / 2, (master.getHeight() - shape.getBounds().height) / 2);
// Any color will do, it could even have an alpha applied
g2d.setColor(Color.BLUE);
// Rotate it a bit, because square is boring...
shape = new Path2D.Double(shape, AffineTransform.getRotateInstance(Math.toRadians(45.0), width / 2, height / 2));
// Fill the area
g2d.fill(shape);
// Rotate again, so you can see that we're compounding the selection
shape = new Path2D.Double(shape, AffineTransform.getRotateInstance(Math.toRadians(45.0), width / 2, height / 2));
// Fill the new selection
g2d.fill(shape);
// Clean up
g2d.dispose();
// Now, apply the mask to the image to get a "cut out"
masked = applyMask(mask, grayScaled, AlphaComposite.SRC_IN);
这是一个简单的例子。当您想要更改选择时,您可以从头开始重新创建遮罩
,或者简单地在原始遮罩
上绘制新对象,然后对灰度
重新应用它以生成新的遮罩
图像
然后,您所需要做的就是在主图像上绘制遮罩的
图像,以您想要的任何alpha级别
“中间灰暗的星星,那是面具;”
您还可以随时将渲染提示应用于其中任何一个,以帮助清理它,因为它都只是图像,所以不会给您带来(许多)问题;) 从内存中,setClip
不会生成“软”edges@MadProgrammer如果您使用setClip
,您将无法从内存中获得抗锯齿的好处,请查看更多想法。您还应该使用Graphics#create
和Graphics#dispose
,这将允许您修改上下文(如使用setClip
)它不会被携带,如果没有更多,很难100%确定code@MadProgrammer感谢这些链接,我将对此进行深入研究,并尝试首先实施这些链接。对不起,Maulin,这可能不是真正的原因,因为我已经在谷歌上搜索了很多次,如果多边形的边界是直线,比如我画了一个正方形或三角形,则不会出现白线矩形将不会有任何白线。因此,我认为它的问题是三角形的抗锯齿谢谢详细描述,我会尝试一下,并尽快让您知道。不要害怕玩弄图像参数的顺序和applyMask的AlphaComposite类型,我花了几次尝试让它实现我想要的;)你可能想了解更多细节。我想我真的需要你的帮助。所有这些图形代码让我发疯。你能帮我吗?如果你感兴趣的话,我可以把我的项目发给你,因为我没有太多时间完成这个项目,实现你的代码看起来很有希望,但我没能完成。我们已经创建了三个缓冲图像,一个是editorimage,用于存储实际图像,一个是灰度图像,另一个是masked,用于存储draw对象和alphacomposite图像。但是这段代码没有达到我们的目标,因为我们也想给绘制的对象上色,但它不接受任何颜色,也不显示我们在运行时绘制的对象中的任何更改。@DilipPoudel如果我理解正确,那么这就可以了
super.paintComponent(g);
grayImage = grayScaleManager.getGrayImage();
BufferedImage mask = new BufferedImage(img.getWidth(),img.getHeight(),BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = mask.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
shadeList.forEach((shape)->{
g2d.setColor(shape.getColor());
if (shape.getColor().getAlpha() != NULL_ALPHA) {
//g2d.fill((Shape)shape);
}
g2d.fill((Shape)shape);
if (shape.getColor().getAlpha() == SELECTION_ALPHA) {
g2d.setStroke(new BasicStroke(1));
g2d.setColor(Color.red.brighter().brighter().brighter());
g2d.draw((Shape) shape);
}
});
// g2d.dispose();
masked = applyMask(mask,grayImage,AlphaComposite.SRC_IN);
g.drawImage(img,0,0,null);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, 0.0f));
g.drawImage(masked, 0, 0, this);
g2d.dispose();
g.dispose();
}
/*Added methods for the changes applymask method*/
public static BufferedImage applyMask(BufferedImage sourceImage, BufferedImage maskImage, int method) {
System.out.println("I am in applymask");
BufferedImage maskedImage = null;
if (sourceImage != null) {
System.out.println("I am in applymask in if case");
int width = maskImage.getWidth(null);
int height = maskImage.getHeight(null);
maskedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D mg = maskedImage.createGraphics();
int x = (width - sourceImage.getWidth(null)) / 2;
int y = (height - sourceImage.getHeight(null)) / 2;
//mg.setColor(Color.RED);
//mg.drawImage(sourceImage, x, y, null);
mg.drawImage(sourceImage, 0, 0, null);
mg.setComposite(AlphaComposite.getInstance(method,0.0f));
mg.dispose();
}
return maskedImage;
}
// The master image or background
master = ImageIO.read(...);
// Generate a gray scaled version of the master image
// This is what we will be cutting out
ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
grayScaled = op.filter(master, null);
int width = master.getWidth() / 4;
int height = master.getHeight() / 4;
// This simply what I'm using as the base "selection"
// But for all intents purpose, it can be anything which can
// be painted through Graphics
Shape shape = new Rectangle2D.Double(0, 0, width, height);
// The base mask, not that it's transparent
BufferedImage mask = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = mask.createGraphics();
// Offset the location to apply the "selection"
g2d.translate((master.getWidth() - shape.getBounds().width) / 2, (master.getHeight() - shape.getBounds().height) / 2);
// Any color will do, it could even have an alpha applied
g2d.setColor(Color.BLUE);
// Rotate it a bit, because square is boring...
shape = new Path2D.Double(shape, AffineTransform.getRotateInstance(Math.toRadians(45.0), width / 2, height / 2));
// Fill the area
g2d.fill(shape);
// Rotate again, so you can see that we're compounding the selection
shape = new Path2D.Double(shape, AffineTransform.getRotateInstance(Math.toRadians(45.0), width / 2, height / 2));
// Fill the new selection
g2d.fill(shape);
// Clean up
g2d.dispose();
// Now, apply the mask to the image to get a "cut out"
masked = applyMask(mask, grayScaled, AlphaComposite.SRC_IN);
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage master;
private BufferedImage grayScaled;
private BufferedImage masked;
public TestPane() {
try {
master = ImageIO.read(...);
ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
grayScaled = op.filter(master, null);
int width = master.getWidth() / 4;
int height = master.getHeight() / 4;
Shape shape = new Rectangle2D.Double(0, 0, width, height);
shape = new Path2D.Double(shape, AffineTransform.getRotateInstance(Math.toRadians(45.0), width / 2, height / 2));
BufferedImage mask = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = mask.createGraphics();
g2d.translate((master.getWidth() - shape.getBounds().width) / 2, (master.getHeight() - shape.getBounds().height) / 2);
g2d.setColor(Color.BLUE);
g2d.fill(shape);
shape = new Path2D.Double(shape, AffineTransform.getRotateInstance(Math.toRadians(45.0), width / 2, height / 2));
g2d.fill(shape);
g2d.dispose();
masked = applyMask(mask, grayScaled, AlphaComposite.SRC_IN);
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public Dimension getPreferredSize() {
return master == null ? getPreferredSize() : new Dimension(master.getWidth(), master.getHeight());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (master != null && masked != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - master.getWidth()) / 2;
int y = (getHeight() - master.getHeight()) / 2;
g2d.drawImage(master, x, y, this);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
g2d.drawImage(masked, x, y, this);
g2d.dispose();
}
}
}
public static BufferedImage applyMask(BufferedImage sourceImage, BufferedImage maskImage, int method) {
BufferedImage maskedImage = null;
if (sourceImage != null) {
int width = maskImage.getWidth(null);
int height = maskImage.getHeight(null);
maskedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D mg = maskedImage.createGraphics();
int x = (width - sourceImage.getWidth(null)) / 2;
int y = (height - sourceImage.getHeight(null)) / 2;
mg.drawImage(sourceImage, x, y, null);
mg.setComposite(AlphaComposite.getInstance(method));
mg.drawImage(maskImage, 0, 0, null);
mg.dispose();
}
return maskedImage;
}
}