我尝试使用相等高度和宽度的drawOval方法,但随着直径增加,圆变得越来越难看。我该怎么做才能让圆无论大小都看起来不错?我该如何在Java中实现反锯齿或其他方法。
我尝试使用相等高度和宽度的drawOval方法,但随着直径增加,圆变得越来越难看。我该怎么做才能让圆无论大小都看起来不错?我该如何在Java中实现反锯齿或其他方法。
事实上,Java2D(我假设这是您正在使用的)已经非常擅长处理此类问题!这里有一个不错的教程:http://www.javaworld.com/javaworld/jw-08-1998/jw-08-media.html
重要的一行是:
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
你可以设置渲染提示:
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
两个可能有用的建议:
java.awt.geom.Ellipse2D
实例,结合 Graphics2D.draw(Shape)
方法代替 Graphics.drawOval
。Graphics2D.setRenderingHint
启用抗锯齿功能。示例:
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Shape theCircle = new Ellipse2D.Double(centerX - radius, centerY - radius, 2.0 * radius, 2.0 * radius);
g2d.draw(theCircle);
}
请参考Josef的答案以了解setRenderingHint
的示例
@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
Ellipse2D.Double hole = new Ellipse2D.Double();
hole.width = 28;
hole.height = 28;
hole.x = 14;
hole.y = 14;
g2d.draw(hole);
}
感谢Oleg Estekhin指出的错误报告,因为它解释了如何做到这一点。
这里有一些小圆圈,在之前和之后。放大几倍以查看像素网格。
向下移动一行,它们会稍微移动子像素量。
第一列没有渲染提示。第二个是仅使用反锯齿。第三个是使用反锯齿和纯模式。
请注意,仅使用反锯齿提示时,前三个圆相同,最后两个圆也相同。似乎发生了一些离散的转换。可能在某个时候进行舍入。
这是代码。为了可读性,它是用Jython编写的,但它驱动Java运行时库,并且可以无损地移植到等效的Java源中,具有完全相同的效果。
from java.lang import *
from java.io import *
from java.awt import *
from java.awt.geom import *
from java.awt.image import *
from javax.imageio import *
bim = BufferedImage(30, 42, BufferedImage.TYPE_INT_ARGB)
g = bim.createGraphics()
g.fillRect(0, 0, 100, 100)
g.setColor(Color.BLACK)
for i in range(5):
g.draw(Ellipse2D.Double(2+0.2*i, 2+8.2*i, 5, 5))
g.setRenderingHint( RenderingHints. KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON)
for i in range(5):
g.draw(Ellipse2D.Double(12+0.2*i, 2+8.2*i, 5, 5))
g.setRenderingHint( RenderingHints. KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE)
for i in range(5):
g.draw(Ellipse2D.Double(22+0.2*i, 2+8.2*i, 5, 5))
#You'll probably want this too later on:
#g.setRenderingHint( RenderingHints. KEY_INTERPOLATION,
# RenderingHints.VALUE_INTERPOLATION_BICUBIC)
#g.setRenderingHint( RenderingHints. KEY_RENDERING,
# RenderingHints.VALUE_RENDER_QUALITY)
ImageIO.write(bim, "PNG", File("test.png"))
总结:您需要同时使用VALUE_ANTIALIAS_ON
和VALUE_STROKE_PURE
才能绘制具有亚像素精度的适当圆形。
编辑日期:2017年9月6日
这是我发明的一种算法,用于在整数矩阵上画圆。相同的思路也可用于在BufferedImage中绘制圆。 如果您正在尝试使用Graphics类绘制该圆形,则这不是您要寻找的答案(除非您希望使用g.drawLine(x,y,x+1,y)修改每个颜色分配,但可能会非常慢)。
protected boolean runOnCircumference(int[][] matrix, int x, int y, int ray, int color) {
boolean ret;
int[] rowUpper = null, rowInferior = null, rowCenterUpper = null, rowCenterInferior = null;
if (ret = ray > 0) {
if (ray == 1) {
matrix[y][x + 1] = color;
rowUpper = matrix[++y];
rowUpper[x] = color;
rowUpper[x + 2] = color;
matrix[y][x] = color;
} else {
double rRay = ray + 0.5;
int r = 0, c = 0, ray2 = ray << 1, ray_1 = ray - 1, halfRay = (ray >> 1) + ray % 2, rInf,
ray1 = ray + 1, horizontalSymmetricOldC;
// draw cardinal points
rowUpper = matrix[ray + y];
rowUpper[x] = color;
rowUpper[x + ray2] = color;
matrix[y][x + ray] = color;
matrix[ray2 + y][x + ray] = color;
horizontalSymmetricOldC = ray1;
rInf = ray2;
c = ray_1;
for (r = 0; r < halfRay; r++, rInf--) {
rowUpper = matrix[r + y];
rowInferior = matrix[rInf + y];
while (c > 0 && (Math.hypot(ray - c, (ray - r)) < rRay)) {
rowUpper[x + c] = color;
rowUpper[x + horizontalSymmetricOldC] = color;
rowInferior[x + c] = color;
rowInferior[x + horizontalSymmetricOldC] = color;
// get the row pointer to optimize
rowCenterUpper = matrix[c + y];
rowCenterInferior = matrix[horizontalSymmetricOldC + y];
// draw
rowCenterUpper[x + r] = color;
rowCenterUpper[x + rInf] = color;
rowCenterInferior[x + r] = color;
rowCenterInferior[x + rInf] = color;
horizontalSymmetricOldC++;
c--;
}
} // end r circle
}
}
return ret;
}
我已经尝试了很多次,手动验证它的正确性,所以我认为它会起作用。我没有进行任何范围检查,只是为了简化代码。 我希望它能帮助你和所有想在矩阵上画圆的人(例如那些试图在纯代码上创建自己的视频游戏并需要管理基于矩阵的游戏地图来存储放置在游戏地图上的对象的程序员[如果您需要帮助,请给我发电子邮件])。