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

前端 未结 7 1132
独厮守ぢ
独厮守ぢ 2020-12-09 12:44

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

相关标签:
7条回答
  • 2020-12-09 12:53

    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))));
    
    0 讨论(0)
  • 2020-12-09 12:59

    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.

    0 讨论(0)
  • 2020-12-09 13:08

    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]);
    
    0 讨论(0)
  • 2020-12-09 13:15

    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;
    }
    
    0 讨论(0)
  • 2020-12-09 13:17

    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;
    }
    
    0 讨论(0)
  • 2020-12-09 13:18

    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.

    0 讨论(0)
提交回复
热议问题