Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4106788

HSBtoRGB method from java.awt.Color class returns incorrect values.

XMLWordPrintable

    • 1.2.2
    • x86
    • windows_nt



      Name: rm29839 Date: 01/26/98


      When converting some colors defined by the RGB model into their equivalent ones in the HSB model -using RGBtoHSB
       method from java.awt.Color class-, to subsequently undo the change through HSBtoRGB method from the same class,
       you can see red, green and blue parameters finally got do not agree with the initial values.

      The next test program reproduces an example of this problem:

      import java.awt.Color;

      public class PruebaColor {

      public static void main (String[] argumentos) {
      System.out.println("PruebaColor");
      System.out.println("©1998 por EMAF");
      System.out.println();
      float[] hsb = new float[3];
      System.out.println("Inicialmente tenemos un color definido por los siguientes parametros:");
      System.out.println(" Rojo (R): 255");
      System.out.println(" Verde (G): 255");
      System.out.println(" Azul (B): 0");
      hsb = Color.RGBtoHSB(255, 255, 0, hsb);
      int rgb = Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]);
      System.out.println("Despues de convertirlo al formato HSB equivalente, mediante el metodo RGBtoHSB");
      System.out.println("de la clase Color, obtenemos de nuevo sus componentes RGB empleando el metodo");
      System.out.println("HSBtoRGB de la misma clase.");
      System.out.println("El resultado obtenido es:");
      System.out.println(" Rojo (R): " + ((rgb & 0x00ff0000) >> 16));
      System.out.println(" Verde (G): " + ((rgb & 0x0000ff00) >> 8));
      System.out.println(" Azul (B): " + (rgb & 0x000000ff));
      System.out.println("Deberiamos haber obtenido el mismo color, pero se observa que la componente");
      System.out.println("roja no es la misma que en el color original.");
      }

      }

      Obviously, this bug will not produce any error messages, it will only return incorrect values in the conversion; so it is very
      difficult to be detected even when the colors obtained appear in the screen in a visual application, since the error magnitude
      is small. In spite of this, the bug can produce important irregularities in graphical applications.
      The number of RGB values generating these incorrect results is very high, as we can see with the next program:

      import java.awt.Color;

      public class LocalizaColores {

      public static void main(String[] argumentos) {

      System.out.println("LocalizaColores");
      System.out.println("©1998 por EMAF");
      System.out.println();
      float[] hsb = new float[3];
      int rgb;
      System.out.println("Valores RGB para los que la doble conversion falla:");
      for (int rojo = 0; rojo <= 255; rojo++) {
      for (int verde = 0; verde <= 255; verde++) {
      for (int azul = 0; azul<= 255; azul++) {
      hsb = Color.RGBtoHSB(rojo, verde, azul, hsb);
      rgb = Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]);
      if ((((rgb & 0x00ff0000) >> 16) != rojo) || (((rgb & 0x0000ff00) >> 8) != verde) || ((rgb & 0x000000ff) != azul)) {
      System.out.println(rojo + ", " + verde + ", " + azul);
      }
      }
      }
      }

      }

      }

      Where is the problem? It is in the HSBtoRGB method. If you examine the source code of this method, you can easily prove that red,
      green and blue values are obtained converting into integer float or double values. In these explicit changes is where the error
      appears due to the direct elimination of the decimals, without rounding up previously.
      The solution could be to make that operation: to round up.

      If we only use values for hue, saturation and brightness coming from a previous RGB to HSB conversion, it would be not necessary
      to round up the expressions (brightness * 255), as it can be mathematically proved. But to cover the general case, in which any
      value can be provided to the HSBtoRGB method, these expressions should be rounded up, too.
      In a nutshell, we could modificate the method in this way:

          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 + .5f);
      } else {
      double h = (hue - Math.floor(hue)) * 6.0;
      double f = h - java.lang.Math.floor(h);
      double p = brightness * (1.0f - saturation);
      double q = brightness * (1.0 - saturation * f);
      double t = brightness * (1.0 - (saturation * (1.0 - f)));
      switch ((int) h) {
      case 0:
      r = (int) (brightness * 255.0f + .5f);
      g = (int) (t * 255.0 + .5);
      b = (int) (p * 255.0 + .5);
      break;
      case 1:
      r = (int) (q * 255.0 + .5);
      g = (int) (brightness * 255.0f + .5f);
      b = (int) (p * 255.0 + .5);
      break;
      case 2:
      r = (int) (p * 255.0 + .5);
      g = (int) (brightness * 255.0f + .5f);
      b = (int) (t * 255.0 + .5);
      break;
      case 3:
      r = (int) (p * 255.0 + .5);
      g = (int) (q * 255.0 + .5);
      b = (int) (brightness * 255.0f + .5f);
      break;
      case 4:
      r = (int) (t * 255.0 + .5);
      g = (int) (p * 255.0 + .5);
      b = (int) (brightness * 255.0f + .5f);
      break;
      case 5:
      r = (int) (brightness * 255.0f + .5f);
      g = (int) (p * 255.0 + .5);
      b = (int) (q * 255.0 + .5);
      break;
      }
      }
      return 0xff000000 | (r << 16) | (g << 8) | (b << 0);
          }

      Although it could be used the round method from java.lang.Math class, it would not be the best way, since for double type
      parameters this function returns long type values that would have to be converted into integer values; in addition the round
      method internally uses the floor method from the same class, not necessary in our case.
      The algorithm could work a little faster if, instead of using double type variables, you use float ones. This will not change the
      results because, in fact, they are going to be finally converted into integer values.
      (Review ID: 23930)
      ======================================================================

            mbronsonsunw Mike Bronson (Inactive)
            rmandelsunw Ronan Mandel (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: