Rogach
Rogach

Reputation: 27250

Why this RadialGradientPaint is drawn incorrectly?

I'm drawing small circles with radial gradient. Example result (r = 10 px):

r=10

But when I decrease the radius, strange things begin to happen. If r = 5px:

r=5

Scaled to match 10px image:

r=5,scaled

And it gets even worse if r = 2px (again, scaled):

enter image description here

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):

enter image description here

"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

Answers (1)

user880855
user880855

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

Related Questions