【问题标题】:Converting from HSV (HSB in Java) to RGB without using java.awt.Color (disallowed on Google App Engine)在不使用 java.awt.Color 的情况下从 HSV(Java 中的 HSB)转换为 RGB(在 Google App Engine 上不允许)
【发布时间】:2011-12-15 07:50:36
【问题描述】:

我想我应该发布这个问题,即使我已经找到了解决方案,因为当我搜索它时 Java 实现并不容易获得。

使用 HSV 代替 RGB 可以生成具有相同饱和度和亮度的颜色(这是我想要的)。

Google App Engine 不允许使用 java.awt.Color,因此无法在 HSV 和 RGB 之间进行以下转换:

Color c = Color.getHSBColor(hue, saturation, value);
String rgb = Integer.toHexString(c.getRGB());

编辑:我按照尼克约翰逊评论中的描述移动了我的答案。

前动画,-亚历山大。

【问题讨论】:

  • 回答您自己的问题很好,但您应该将答案发布为作为答案,而不是作为问题的一部分。
  • 谢谢尼克,我明天会这样做并编辑问题。 (目前我收到错误消息:“声誉低于 100 的用户在提问后 8 小时内无法回答自己的问题。您可以在 6 小时内自行回答。在此之前请使用 cmets,或改为编辑您的问题” )

标签: java google-app-engine colors rgb hsv


【解决方案1】:

我对颜色数学一无所知,但我可以为代码提供这种替代结构,这让我的审美感觉很痒,因为它让我很清楚这 6 种情况中的每一种只是价值的不同排列, t 和 p。 (而且我对长长的 if-else 链有一种非理性的恐惧。)

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

【讨论】:

  • 这确实更漂亮,只是以调用另一个方法为代价。
  • 我很乐观,编译器或 JIT 将内联额外的方法,如果它是一个主要的性能提升。
  • 抱歉拖了一个 2 年前的帖子,但我想知道是否有人会为我确认一些事情 - rgbToString 应该乘以 255,而不是 256?因为否则,当r1.0 时,rs 将是十六进制的100,这是错误的。
  • 是的,虽然如果你只是乘以 255,那么像 0.9999 这样的结果将被截断为 254,这也是不正确的。正确的算法将实现 java.awt.Color.HSBtoRGB() 中存在的舍入
  • 如果您的色调值正好是 1,那么 h 很容易为 6,从而引发不必要的异常。
【解决方案2】:

您应该使用 Oracle 提供的 HSBtoRGB 实现,将其源代码复制到您的项目中。 java.awt.Color 是开源的。 Peter Recore 和 Yngling 提供的算法并不稳健,并且会为某些输入返回非法的 RGB 值,例如“256,256,0”。 Oracle 的实现很健壮,请改用它。

【讨论】:

    【解决方案3】:

    使用ColorUtils 提供

    HSLToColor(float\[\] hsl) 
    

    还有

    [RGBToHSL(int r, int g, int b, float\[\] hsl)]
    

    很容易相互转换的方法!

    例如:

    float[] hsl = new float[]{1.5, 2.0, 1.5};
    int color = ColorUtils.HSLToColor(hsl);
    

    现在获取颜色

    float[] hslStub = new float[3];
    float[] hslFromColor = ColorUtils.colorToHSL(color, hslStub);
    

    现在获取 hsl

    这里是sourcecode

    【讨论】:

      【解决方案4】:

      解决方案在这里找到:http://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/

      Martin Ankerl 提供了一篇关于该主题的好文章,并提供了 Ruby 脚本。对于那些忙(或懒)用Java实现它的人,这是我做的(我相信它可以写得更有效,请随意评论):

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

      【讨论】:

      • 最后一个 else 条件应该是| else if (h &lt;= 6) {。并且转换应该是 (r * 255) 等而不是 * 256,因为颜色范围是 0 到 255。
      • @ehartwell:根据您的 cmets 编辑。
      【解决方案5】:

      我的转换代码:

           /**
           * @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;
          }
      

      Android 上的使用示例:

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

      【讨论】:

        【解决方案6】:

        @Peter Recore 的答案不使用四舍五入。

        可能更正确的使用方法是从 java.awt.Color 复制内容,这就是它在 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);
            }
        

        这里的四舍五入似乎是正确的。

        【讨论】:

          【解决方案7】:

          使用 SWT 你可以使用以下代码 sn-p:

          RGB rgb = new RGB(r, g, b);
          float[] hsbColor = rgb.getHSB();
          rgb = new RGB(hsbColor[0], hsbColor[1], hsbColor[2]);
          

          【讨论】:

          • 已确认。虽然 (int,int,int) 构造函数接受 RGB,但 (float,float,float) 构造函数接受 HSB。
          猜你喜欢
          • 2015-03-11
          • 1970-01-01
          • 2019-06-21
          • 1970-01-01
          • 2017-12-02
          • 2011-03-26
          • 2012-04-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多