Converting from HSV (HSB in Java) to RGB without using java.awt.Color (disallowed on Google App Engine)
Solution 1
I don't know anything about color math, but I can offer this alternative structure for the code, which tickles my aesthetic sense because it made it obvious to me how each of the 6 cases is just a different permutation of value, t and p. (Also I have an irrational fear of long if-else chains.)
public static String hsvToRgb(float hue, float saturation, float value) {
int h = (int)(hue * 6);
float f = hue * 6 - h;
float p = value * (1 - saturation);
float q = value * (1 - f * saturation);
float t = value * (1 - (1 - f) * saturation);
switch (h) {
case 0: return rgbToString(value, t, p);
case 1: return rgbToString(q, value, p);
case 2: return rgbToString(p, value, t);
case 3: return rgbToString(p, q, value);
case 4: return rgbToString(t, p, value);
case 5: return rgbToString(value, p, q);
default: throw new RuntimeException("Something went wrong when converting from HSV to RGB. Input was " + hue + ", " + saturation + ", " + value);
}
}
public static String rgbToString(float r, float g, float b) {
String rs = Integer.toHexString((int)(r * 256));
String gs = Integer.toHexString((int)(g * 256));
String bs = Integer.toHexString((int)(b * 256));
return rs + gs + bs;
}
Solution 2
You should use the HSBtoRGB implementation provided by Oracle, copying its source code into your project. java.awt.Color is open-source. The algorithms provided by Peter Recore and Yngling are not robust and will return illegal RGB values like "256,256,0" for certain inputs. Oracle's implementation is robust, use it instead.
Solution 3
Use ColorUtils which provides
HSLToColor(float\[\] hsl)
And
[RGBToHSL(int r, int g, int b, float\[\] hsl)]
Methods which are very easy to convert to each other!
For example:
float[] hsl = new float[]{1.5, 2.0, 1.5};
int color = ColorUtils.HSLToColor(hsl);
Now get the color
float[] hslStub = new float[3];
float[] hslFromColor = ColorUtils.colorToHSL(color, hslStub);
Now get the hsl
Here is the sourcecode.
Solution 4
The solution was found here: http://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
Martin Ankerl provides a good post on the subject, and provides Ruby script. For those too busy (or lazy) to implement it in Java, here's the one I did (I am sure it can be written more effectively, please feel free to comment):
public static String hsvToRgb(float hue, float saturation, float value) {
float r, g, b;
int h = (int)(hue * 6);
float f = hue * 6 - h;
float p = value * (1 - saturation);
float q = value * (1 - f * saturation);
float t = value * (1 - (1 - f) * saturation);
if (h == 0) {
r = value;
g = t;
b = p;
} else if (h == 1) {
r = q;
g = value;
b = p;
} else if (h == 2) {
r = p;
g = value;
b = t;
} else if (h == 3) {
r = p;
g = q;
b = value;
} else if (h == 4) {
r = t;
g = p;
b = value;
} else if (h <= 6) {
r = value;
g = p;
b = q;
} else {
throw new RuntimeException("Something went wrong when converting from HSV to RGB. Input was " + hue + ", " + saturation + ", " + value);
}
String rs = Integer.toHexString((int)(r * 255));
String gs = Integer.toHexString((int)(g * 255));
String bs = Integer.toHexString((int)(b * 255));
return rs + gs + bs;
}
Solution 5
Using SWT you can use following code snippet:
RGB rgb = new RGB(r, g, b);
float[] hsbColor = rgb.getHSB();
rgb = new RGB(hsbColor[0], hsbColor[1], hsbColor[2]);
yngling
Programmer, Pankratiast, Pâtissier, PhD student, Political animal & Prospective Entrepreneur.
Updated on May 19, 2020Comments
-
yngling almost 4 years
I figured I should post this question, even if I have already found a solution, as a Java implementation was not readily available when I searched for it.
Using HSV instead of RGB allows the generation of colors with the same saturation and brightness (something I wanted).
Google App Engine does not allow use of java.awt.Color, so doing the following to convert between HSV and RGB is not an option:
Color c = Color.getHSBColor(hue, saturation, value); String rgb = Integer.toHexString(c.getRGB());
Edit: I moved my answer as described in the comment by Nick Johnson.
Ex animo, - Alexander.
-
yngling over 12 yearsThat is indeed a lot prettier, at the mere cost of another method invocation.
-
Peter Recore over 12 yearsI'm optimistic that either the compiler or the JIT would inline the extra method if it were a major performance gain.
-
devrobf over 10 yearsSorry to drag up a 2 year old thread, but I wondered if someone would confirm something for me - should
rgbToString
multiply by255
, not256
? Because otherwise, whenr
is1.0
,rs
would be100
in hex, which is wrong. -
piepera over 10 yearsYes, although if you simply multiply by 255, then results like 0.9999 will get truncated to 254, which is not correct either. A correct algorithm would implement the rounding present in java.awt.Color.HSBtoRGB()
-
ehartwell over 9 yearsThe last else condition should probably say
| else if (h <= 6) {
. And the conversion should be(r * 255)
etc not* 256
since the color range is 0 to 255. -
ehartwell over 9 yearsIf your hue value is exactly 1, then h could easily be 6, throwing an unnecessary exception.
-
Peter O. almost 9 years@ehartwell: Edited based on your comments.
-
Aaron Spalding about 8 yearsTake a look at github.com/sualeh/SchemaCrawler/blob/… for a complete realization of the code above, which takes into account round results, and having the hue be any float.
-
Andy Thomas over 2 yearsConfirmed. Although the
(int,int,int)
constructor accepts RGB, the(float,float,float)
constructor accepts HSB. -
Jitendra Mistry almost 2 yearshello are you still alive??