Converting from HSV (HSB in Java) to RGB without using java.awt.Color (disallowed on Google App Engine)

∥☆過路亽.° 提交于 2019-11-28 08:36:59

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;
}

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.

cafecat

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.

My code for converting:

     /**
     * @param H
     *            0-360
     * @param S
     *            0-100
     * @param V
     *            0-100
     * @return color in hex string
     */
    public static String hsvToRgb(float H, float S, float V) {

        float R, G, B;

        H /= 360f;
        S /= 100f;
        V /= 100f;

        if (S == 0)
        {
            R = V * 255;
            G = V * 255;
            B = V * 255;
        } else {
            float var_h = H * 6;
            if (var_h == 6)
                var_h = 0; // H must be < 1
            int var_i = (int) Math.floor((double) var_h); // Or ... var_i =
                                                            // floor( var_h )
            float var_1 = V * (1 - S);
            float var_2 = V * (1 - S * (var_h - var_i));
            float var_3 = V * (1 - S * (1 - (var_h - var_i)));

            float var_r;
            float var_g;
            float var_b;
            if (var_i == 0) {
                var_r = V;
                var_g = var_3;
                var_b = var_1;
            } else if (var_i == 1) {
                var_r = var_2;
                var_g = V;
                var_b = var_1;
            } else if (var_i == 2) {
                var_r = var_1;
                var_g = V;
                var_b = var_3;
            } else if (var_i == 3) {
                var_r = var_1;
                var_g = var_2;
                var_b = V;
            } else if (var_i == 4) {
                var_r = var_3;
                var_g = var_1;
                var_b = V;
            } else {
                var_r = V;
                var_g = var_1;
                var_b = var_2;
            }

            R = var_r * 255; // RGB results from 0 to 255
            G = var_g * 255;
            B = var_b * 255;
        }

        String rs = Integer.toHexString((int) (R));
        String gs = Integer.toHexString((int) (G));
        String bs = Integer.toHexString((int) (B));

        if (rs.length() == 1)
            rs = "0" + rs;
        if (gs.length() == 1)
            gs = "0" + gs;
        if (bs.length() == 1)
            bs = "0" + bs;
        return "#" + rs + gs + bs;
    }

Example of use on Android:

tv.setBackgroundColor(Color.parseColor((ColorOperations.hsvToRgb(100, 100, 57))));

The answer by @Peter Recore do not use rounding.

Probably somewhat more correct way to use it is to copy the content from java.awt.Color and this is how it looked in Java 6:

 public static int HSBtoRGB(float hue, float saturation, float brightness) {
        int r = 0, g = 0, b = 0;
        if (saturation == 0) {
            r = g = b = (int) (brightness * 255.0f + 0.5f);
        } else {
            float h = (hue - (float)Math.floor(hue)) * 6.0f;
            float f = h - (float)java.lang.Math.floor(h);
            float p = brightness * (1.0f - saturation);
            float q = brightness * (1.0f - saturation * f);
            float t = brightness * (1.0f - (saturation * (1.0f - f)));
            switch ((int) h) {
            case 0:
                r = (int) (brightness * 255.0f + 0.5f);
                g = (int) (t * 255.0f + 0.5f);
                b = (int) (p * 255.0f + 0.5f);
                break;
            case 1:
                r = (int) (q * 255.0f + 0.5f);
                g = (int) (brightness * 255.0f + 0.5f);
                b = (int) (p * 255.0f + 0.5f);
                break;
            case 2:
                r = (int) (p * 255.0f + 0.5f);
                g = (int) (brightness * 255.0f + 0.5f);
                b = (int) (t * 255.0f + 0.5f);
                break;
            case 3:
                r = (int) (p * 255.0f + 0.5f);
                g = (int) (q * 255.0f + 0.5f);
                b = (int) (brightness * 255.0f + 0.5f);
                break;
            case 4:
                r = (int) (t * 255.0f + 0.5f);
                g = (int) (p * 255.0f + 0.5f);
                b = (int) (brightness * 255.0f + 0.5f);
                break;
            case 5:
                r = (int) (brightness * 255.0f + 0.5f);
                g = (int) (p * 255.0f + 0.5f);
                b = (int) (q * 255.0f + 0.5f);
                break;
            }
        }
        return 0xff000000 | (r << 16) | (g << 8) | (b << 0);
    }

Rounding here seems to be correct.

yngling

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;
}

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]);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!