2

I have code that converts RGB values to HSL values as well as HSL to RGB. It works fine, however, I have a color picker that can work in either rgb or hsl. The problem is, that they both use integer values..

So if I convert RGB to HSL, I get fractions that need to be rounded. When I convert back to RGB, the values aren't the same as they were- a number is usually of by one (a value of 123 might become 124 after going RGB>HSL>RGB).

I find this odd because in Photoshop, they have the same color picker- you can choose between RGB and HSB, and when you convert back and forth, the RGB values remain consistent and they use integer values when you pick in both modes. How do they accomplish that?

user3591153
  • 409
  • 4
  • 14
  • I would suggest storing RGB *and* HSL values, plus a flag to indicate which is active. Otherwise consistency would be impossible to maintain. (For example, with a saturation value of zero, all hue values are equivalent.) – r3mainer Aug 02 '17 at 22:26
  • yes, I am doing that- however, the problem occurs when I want to switch picker modes. The values change, because the fractions become whole numbers. I don't want to have to specify fractions in the picker. So I'm wondering how to keep those fractions hidden, yet still be able to pick and convert to the same values as you had picked in the past. Photoshop does that somehow.. – user3591153 Aug 02 '17 at 22:31
  • 1
    How about continuing to use the RGB values when the user switches to HSL, and only using HSL values if and when the user moves the colour selection cursor in the HSL dialog? – r3mainer Aug 02 '17 at 22:37
  • If you have a `Color` abstract class with `as_rgb` and `as_hsl` methods, you can then have `RGBColor` and `HSLColor` inherit from that, implementing one function trivially and the other as a conversion. Then you can keep it as the selected color until a new one is selected. – Daniel H Aug 02 '17 at 22:40
  • I guess I could keep a list of used colors with their rgb values, and if a color is defined using hsl, I could check that list for similar color and convert that rgb to the hsl integer values. That way the HSL picker will be reliant on previously used RGB values. – user3591153 Aug 02 '17 at 22:52

1 Answers1

3

The color spaces do not have the same size for integral values.

HSL has black (lighness zero), plus white (lightness 100), plus 359 * 100 * 98 other colors (since hue zero is the same as hue 360), making 3,518,202 integer triples.

RGB has 256 * 256 * 256, or 16,777,216 integer triples, so multiple RGB values can map to the same HSL value - in the ration of about 4.7 to 1.

To maintain consistency when changing picker modes you may need to maintain HSL values as floating point values internally, but show integer values in the picker. Maintaining RGB values as floating point internally may help as well.

Another issue I have seen in color software is to round RGB values obtained from HSL to RGB conversion to the nearest integer in the range 0 to 255. I regard this as problematic because it means rgb values 1 to 254 contain 1/255th of the range, while zero and 255 only get half of 1/255th of the range each. The alternative I preferred was to map floating point RGB component values of 256 to 255 (or 255.99999 if you wish) and take the integer floor of the resultant color component. That way integer component values of 0 to 255 get (1/256)th of the range each.

At the end of the day, if you wanted users to be able to enter an HSL value that they used before and get exactly the same color, you would need to allow HSL values with decimal places.

traktor
  • 17,588
  • 4
  • 32
  • 53