Reputation: 43
I am trying to draw a RGB color wheel in Java, but I can't get the gradient by a circular shape. I just want to draw it on screen, with no user interaction at all.
This is all I have for now:
public void paint (Graphics g){
super.paint(g);
int red = 255;
int green = 0;
int blue = 0;
int x1 = 500;
int y1 = 305;
int x2 = 500;
int y2 = 50;
while (green != 255){
g.setColor(new Color(red, green, blue));
green++;
g.drawLine(x1, y1, x2, y2);
x2++;
if (y2 < y1){
y2++;
}
}
while (red != 0){
g.setColor(new Color(red, green, blue));
red--;
g.drawLine(x1, y1, x2, y2);
x2--;
y2++;
}
x2 = 500;
while (blue != 255){
g.setColor(new Color(red, green, blue));
blue++;
g.drawLine(x1, y1, x2, y2);
x2--;
if (y2 > y1){
y2--;
}
}
while (red != 255){
green--;
g.setColor(new Color(red, green, blue));
red++;
g.drawLine(x1, y1, x2, y2);
x2++;
y2--;
}
}
}
Which draws the gradient like this
This is what I want
Upvotes: 2
Views: 7193
Reputation: 1
The color wheel is easy if we use HSB instead of RGB. We must define every single pixel. The hue is set by the angle, so, first we calculate the angle with the atan2 function, and then the hue is angle / 2pi. The saturation is set by the distance to the center, then, saturation = distance / radius. Brightness is equal for every pixel, so we say 1. With these three values, we can convert the color to RGB with the HSBtoRGB function. This is my code:
BufferedImage createWheelBuffer(int radius) {
final int diameter = radius * 2;
final double radius2 = radius * radius;
float hue, sat;
final double PI2 = 2 * Math.PI;
double dist2;
int rgb;
BufferedImage buffer = new BufferedImage(diameter, diameter, BufferedImage.TYPE_INT_ARGB);
for (int x = 0; x < diameter; x++) {
for (int y = 0; y < diameter; y++) {
dist2 = distance2(x, y, radius, radius);
// if the point is not inside the circle we go to the next point
if (dist2 > radius2) continue;
hue = (float) (Math.atan2(y - radius, x - radius) / PI2);
sat = (float) Math.sqrt((float) dist2) / (float) radius;
rgb = Color.HSBtoRGB(hue, sat, 1);
buffer.setRGB(x, y, rgb);
}
}
return buffer;
}
int distance2(int x1, int y1, int x2, int y2) {
int a = x2 - x1;
int b = y2 - y1;
return a * a + b * b;
}
And in the paintComponent event:
protected void paintComponent(Graphics gr) {
super.paintComponent(gr);
Graphics2D g = (Graphics2D) gr;
BufferedImage buffer = createWheelBuffer(radius);
g.drawImage(buffer, x, y, this);
}
Upvotes: 0
Reputation: 454
Here is my solution for drawing a RGB Color Wheel in Java:
public class Main {
public static void main(String[] args) {
int rad = 1024;
BufferedImage img = new BufferedImage(rad, rad, BufferedImage.TYPE_INT_RGB);
// Center Point (MIDDLE, MIDDLE)
int centerX = img.getWidth() / 2;
int centerY = img.getHeight() / 2;
int radius = (img.getWidth() / 2) * (img.getWidth() / 2);
// Red Source is (RIGHT, MIDDLE)
int redX = img.getWidth();
int redY = img.getHeight() / 2;
int redRad = img.getWidth() * img.getWidth();
// Green Source is (LEFT, MIDDLE)
int greenX = 0;
int greenY = img.getHeight() / 2;
int greenRad = img.getWidth() * img.getWidth();
// Blue Source is (MIDDLE, BOTTOM)
int blueX = img.getWidth() / 2;
int blueY = img.getHeight();
int blueRad = img.getWidth() * img.getWidth();
for (int i = 0; i < img.getWidth(); i++) {
for (int j = 0; j < img.getHeight(); j++) {
int a = i - centerX;
int b = j - centerY;
int distance = a * a + b * b;
if (distance < radius) {
int rdx = i - redX;
int rdy = j - redY;
int redDist = (rdx * rdx + rdy * rdy);
int redVal = (int) (255 - ((redDist / (float) redRad) * 256));
int gdx = i - greenX;
int gdy = j - greenY;
int greenDist = (gdx * gdx + gdy * gdy);
int greenVal = (int) (255 - ((greenDist / (float) greenRad) * 256));
int bdx = i - blueX;
int bdy = j - blueY;
int blueDist = (bdx * bdx + bdy * bdy);
int blueVal = (int) (255 - ((blueDist / (float) blueRad) * 256));
Color c = new Color(redVal, greenVal, blueVal);
float hsbVals[] = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
Color highlight = Color.getHSBColor(hsbVals[0], hsbVals[1], 1);
img.setRGB(i, j, RGBtoHEX(highlight));
} else {
img.setRGB(i, j, 0xFFFFFF);
}
}
}
try {
ImageIO.write(img, "png", new File("wheel.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
public static int RGBtoHEX(Color color) {
String hex = Integer.toHexString(color.getRGB() & 0xffffff);
if (hex.length() < 6) {
if (hex.length() == 5)
hex = "0" + hex;
if (hex.length() == 4)
hex = "00" + hex;
if (hex.length() == 3)
hex = "000" + hex;
}
hex = "#" + hex;
return Integer.decode(hex);
}
}
Upvotes: 3
Reputation: 6173
From here, it seems like the easiest way to brighten a color is by converting it to HSB.
float hsbVals[] = Color.RGBtoHSB( originalColor.getRed(),
originalColor.getGreen(),
originalColor.getBlue(), null );
Color highlight = Color.getHSBColor( hsbVals[0], hsbVals[1],
0.5f * ( 1f + hsbVals[2] )); // Play with this part to modify rate of change
From what you have, it looks like you essentially need to erase all but a circular region in the middle.
From this answer, it seems like the Area class is easiest.
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g.create();
Rectangle2D rectangleNotToDrawIn = new Rectangle2D.Double(100, 100, 20, 30);
// You will need to find out what size ellipse you need
Area outside = calculateOutside(rectangleNotToDrawIn);
// draw color wheel here
g2.setPaint(Color.black); // assuming you want black
g2.setClip(outside);
g2.drawLine(0, 0, getWidth(), getHeight());
}
// Change this method to take in an ellipse shape.
private Area calculateOutside(Rectangle2D r) {
Area outside = new Area(new Rectangle2D.Double(0, 0, getWidth(), getHeight()));
outside.subtract(new Area(r));
return outside;
}
Upvotes: 2