Reputation: 27250
I'm drawing small circles with radial gradient. Example result (r
= 10 px):
But when I decrease the radius, strange things begin to happen. If r
= 5px:
Scaled to match 10px image:
And it gets even worse if r = 2px (again, scaled):
As you see, the center of the gradient is consistently off (down and to the right) from center of circle.
The code I used to generate the above images (SSCCE, compilable&runnable):
import java.awt.image.*;
import javax.imageio.ImageIO;
import java.io.File;
import java.awt.*;
import java.awt.geom.*;
public class Test {
public static void main(String[] args) throws Exception {
float r = 2;
BufferedImage img = new BufferedImage((int) r*4, (int) r*4, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = img.createGraphics();
RenderingHints rh = new RenderingHints(null);
rh.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
rh.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
rh.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.addRenderingHints(rh);
g.setBackground(Color.WHITE);
g.clearRect(0, 0, (int) r*4, (int) r*4);
g.setPaint(new RadialGradientPaint(
r*2,r*2,r*2,
new float[] {0.1f,0.35f},
new Color[] {Color.RED, Color.GREEN}
));
g.fill(new Ellipse2D.Float(r,r,r*2,r*2));
g.dispose();
ImageIO.write(img, "png", new File("out.png"));
}
}
I tried switching rendering hints, but the result doesn't change. What could be causing this problem?
EDIT:
Offsetting RadialGradientPaint by 0.5f
top-left results in correct image (r=2):
"Fixed" code:
g.setPaint(new RadialGradientPaint(
r*2-0.5f, r*2-0.5f, r*2,
new float[] {0.1f,0.35f},
new Color[] {Color.RED, Color.GREEN}
));
Upvotes: 0
Views: 886
Reputation:
The problem has to do with the fact that the height and width of your circle is an even number. You used to have g.fill(new Ellipse2D.Float(r,r,r*2,r*2));
as part of your code. This made it so that the width and height of your circle was always even. This causes problems because computers are not perfect and its not possible to draw a pixel exactly in the center of a circle with even dimensions. To fix this, I added one to where you drew your circle. The working code follows:
import java.awt.image.*;
import javax.imageio.ImageIO;
import java.io.File;
import java.awt.*;
import java.awt.geom.*;
public class Test {
public static void main(String[] args) throws Exception {
float r = 2;
BufferedImage img = new BufferedImage((int) r*4 + 1, (int) r*4 + 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = img.createGraphics();
RenderingHints rh = new RenderingHints(null);
rh.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
rh.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
rh.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.addRenderingHints(rh);
g.setBackground(Color.WHITE);
g.clearRect(0, 0, (int) r*4 + 1, (int) r*4 + 1);
g.setPaint(new RadialGradientPaint(
r*2,r*2,r*2,
new float[] {0.1f,0.35f},
new Color[] {Color.RED, Color.GREEN}
));
g.fill(new Ellipse2D.Float(r,r,r*2 + 1,r*2 + 1));
g.dispose();
ImageIO.write(img, "png", new File("out.png"));
}
}
Upvotes: 1