Link to home
Start Free TrialLog in
Avatar of zuppy
zuppyFlag for Italy

asked on

RGB to & from HLS coversion alghoritm

I must work with colors.
I need the alghoritm that makes conversion RGB <-> HLS

For ex. if I have RGB color 125-160-233 I want to know the corrispondent in HLS and viceversa.
Hoping someone can help me :D

Avatar of Deathead
Deathead

I have been doing this for 4 years and this is my first time hearing HLS.. please explain and I would love to help you
~X. Deathead
Avatar of Michel Plungjan
Hue, saturation, Lightness ;-)

HSB is more likely.

Here is a java one.

I do alas not have time to convert it to javascript


/**
     * Converts the components of a color, as specified by the HSB
     * model, to an equivalent set of values for the default RGB model.
     * <p>
     * The integer that is returned by <code>HSBtoRGB</code> encodes the
     * value of a color in bits 0&endash;23 of an integer value, the same
     * format used by the method <code>getRGB</code>. This integer can be
     * supplied as an argument to the <code>Color</code> constructor that
     * takes a single integer argument.
     * @param     hue   the hue component of the color.
     * @param     saturation   the saturation of the color.
     * @param     brightness   the brightness of the color.
     * @return    the RGB value of the color with the indicated hue,
     *                            saturation, and brightness.
     * @see       java.awt.Color#getRGB()
     * @see       java.awt.Color#Color(int)
     * @see       java.awt.image.ColorModel#getRGBdefault()
     * @since     JDK1.0
     */
    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);
    }

    /**
     * Converts the components of a color, as specified by the default RGB
     * model, to an equivalent set of values for hue, saturation, and
     * brightness, the three components of the HSB model.
     * <p>
     * If the <code>hsbvals</code> argument is <code>null</code>, then a
     * new array is allocated to return the result. Otherwise, the method
     * returns the array <code>hsbvals</code>, with the values put into
     * that array.
     * @param     r   the red component of the color.
     * @param     g   the green component of the color.
     * @param     b   the blue component of the color.
     * @param     hsbvals  the array to be used to return the
     *                     three HSB values, or <code>null</code>.
     * @return    an array of three elements containing the hue, saturation,
     *                     and brightness (in that order), of the color with
     *                     the indicated red, green, and blue components.
     * @see       java.awt.Color#getRGB()
     * @see       java.awt.Color#Color(int)
     * @see       java.awt.image.ColorModel#getRGBdefault()
     * @since     JDK1.0
     */
    public static float[] RGBtoHSB(int r, int g, int b, float[] hsbvals) {
 float hue, saturation, brightness;
 if (hsbvals == null) {
     hsbvals = new float[3];
 }
     int cmax = (r > g) ? r : g;
 if (b > cmax) cmax = b;
 int cmin = (r < g) ? r : g;
 if (b < cmin) cmin = b;

 brightness = ((float) cmax) / 255.0f;
 if (cmax != 0)
     saturation = ((float) (cmax - cmin)) / ((float) cmax);
 else
     saturation = 0;
 if (saturation == 0)
     hue = 0;
 else {
     float redc = ((float) (cmax - r)) / ((float) (cmax - cmin));
     float greenc = ((float) (cmax - g)) / ((float) (cmax - cmin));
     float bluec = ((float) (cmax - b)) / ((float) (cmax - cmin));
     if (r == cmax)
  hue = bluec - greenc;
     else if (g == cmax)
         hue = 2.0f + redc - bluec;
            else
  hue = 4.0f + greenc - redc;
     hue = hue / 6.0f;
     if (hue < 0)
  hue = hue + 1.0f;
 }
 hsbvals[0] = hue;
 hsbvals[1] = saturation;
 hsbvals[2] = brightness;
 return hsbvals;
    }
Avatar of zuppy

ASKER

Yeah, interesting but I have a bit difficulty because I've never worked in Java :(
 (I had not idea that the alghoritm was so complicated)
Avatar of zuppy

ASKER

BUt for make all easy I need mainly HSB (sorry for HSL but I translated from Italian)
I can try to convert it tomorrow if you can wait.

Michel

Avatar of zuppy

ASKER

Yeah... (for me is just tomorrow here :P)
I used to work on Optical Spectrum Analysers, and have the formulae for RGB/HSB & HSB/RGB conversion here.

As you can see, the javascript is actually a slight part simpler than the java, because of the loose typing of the language.

By the way, the most widely used acronym for the HSB colour space is actually HLS. It also goes under the acronym HSI.

 HLS = Hue, Luminance, Saturation
 HSB = Hue, Saturation, Brightness
 HSI = Hue, Saturation, Intensity

Luminance = Saturation = Intensity.

Here ya go:
--
<html>
 <head>
  <script language="javascript"> <!--

function HSBtoRGB( hue, sat, bri ) {
 var r,g,b;
 var x1,x2,x3,x4,x5;
 var b2 = bri * 255;
 var b3 = Math.round( b2 );

 if( sat == 0 ) {
  r = g = b = b3;
 }
 else {
  var x1 = (hue - Math.floor(hue)) * 6;
  var x2 = x1 - Math.floor(x1);
  var x3 = Math.round( b2 * ( 1 - sat ) );
  var x4 = Math.round( b2 * ( 1 - sat * x2 ) );
  var x5 = Math.round( b2 * ( 1 - sat * ( 1 - x2 )) );

  switch( parseInt(x1, 10) ) {
   case 0: r = b3; g = x5; b = x3; break;
   case 1: r = x4; g = b3; b = x3; break;
   case 2: r = x3; g = b3; b = x5; break;
   case 3: r = x3; g = x4; b = b3; break;
   case 4: r = x5; g = x3; b = b3; break;
   case 5: r = b3; g = x3; b = x4; break;
  }
 }
 return new Array(r,g,b);
}

function RGBtoHSB( r, g, b ) {
 var mx = Math.max( r, Math.max(g, b) );
 var mn = Math.min( r, Math.min(g, b) );
 var cd = mx-mn;
 var bri = mx / 255;
 var sat = (mx == 0) ? 0 : (cd / mx);
 var hue;

 if( sat == 0 )
  hue = 0;
 else {
  var rc = (mx-r) / cd;
  var gc = (mx-g) / cd;
  var bc = (mx-b) / cd;

  if( r == mx )
   hue = bc - gc;
  else if( g == mx)
   hue = 2 + rc - bc;
  else
   hue = 4 + gc - rc;

  hue /= 6;
  if( hue < 0)
   hue += 1;
 }
 return new Array( hue, sat, bri);
}

// Example follows :

rr = 25; gg = 50; bb = 75;

rgb1 = new Array( rr, gg, bb );
hsb1 = RGBtoHSB( rr, gg, bb );
hh = hsb1[0]; ss = hsb1[1]; br = hsb1[2];
rgb2 = HSBtoRGB( hh, ss, br );

dw = "started with RGB of (" + rgb1 + ")<br>";
dw = dw + "converted to HSB of (" + hsb1 + ")<br>";
dw = dw + "back to RGB of (" + rgb2 + ")";

document.write( dw );
// -->
</script>
</head>
</html>
--

For each function, you pass the triplet of values, and you are returned an array of the triplet values you required.

Brian
Yes, I could see that, but I didn't have the time to remove all the f's and floats ;-)

Michel
Avatar of zuppy

ASKER

Mumble mumble....
I've tried you function but seems work fine only with (0,0,bri)

Try this exemple code (tried under NN but it shoul work fine under IE):

a make a continuous cicle from 0 to 100 to change Brightness of two 100x100 trasparent gifs.

this is what i expected

black --> gray   (from darkner to lighter)   ->white
black --> yellow (from darkner to lighter)   ->white


But , as you can see the yellow one stop becoming white.

Maybe I mispelled something?

I think your function range values must be 0 to 1.

My need was to have al kind of yellow (or other color) fixed H and S and working with B.


<html>
<head>
<STYLE>
..tipo4 {
font-family:    times;
font-size:      48px;
color:          #ffffff;
position:       absolute;
top:            140px;
left:           10px;
width:          100px;
height:         100px;
visibility:     visible;
z-index:        1;
}

..tipo5 {
font-family:    times;
font-size:      48px;
color:          #ffffff;
position:       absolute;
top:            140px;
left:           110px;
width:          100px;
height:         100px;
visibility:     visible;
z-index:        1;
}
</STYLE>

<SCRIPT>

luminosity=0;

function HSBtoRGB( hue, sat, bri ) {

var r,g,b;
var x1,x2,x3,x4,x5;
var b2 = bri * 255;
var b3 = Math.round( b2 );

if( sat == 0 ) { r = g = b = b3; }
else {
   var x1 = (hue - Math.floor(hue)) * 6;
   var x2 = x1 - Math.floor(x1);
   var x3 = Math.round( b2 * ( 1 - sat ) );
   var x4 = Math.round( b2 * ( 1 - sat * x2 ) );
   var x5 = Math.round( b2 * ( 1 - sat * ( 1 - x2 )) );

      switch( parseInt(x1, 10) ) {
          case 0: r = b3; g = x5; b = x3; break;
          case 1: r = x4; g = b3; b = x3; break;
          case 2: r = x3; g = b3; b = x5; break;
          case 3: r = x3; g = x4; b = b3; break;
          case 4: r = x5; g = x3; b = b3; break;
          case 5: r = b3; g = x3; b = x4; break;
         }
    }

r = r.toString(16);
if (r.length == 1) r = '0' + r;
g = g.toString(16);
if (g.length == 1) g = '0' + g;
b = b.toString(16);
if (b.length == 1) b = '0' + b;

rgb="#"+r+g+b;

//here conversion to #RRGGBB base 16

return rgb;
 }


function dec2virg(value)
{
quantity=value/100;
return quantity;
}


function colore()
{
var isNS = (navigator.appName == "Netscape" && parseInt(navigator.appVersion) >= 4);
var trasp = (isNS) ? document.trasp : document.all.trasp.style;
var trasp2 = (isNS) ? document.trasp2 : document.all.trasp2.style;

luminosity++;
if (luminosity >100){luminosity=0;}


if (isNS)
      {
      trasp.bgColor=HSBtoRGB(.125,.9058,dec2virg(luminosity));
      trasp2.bgColor=HSBtoRGB(0,0,dec2virg(luminosity));
      }
      else
      {
      trasp.backgroundColor=HSBtoRGB(.125,.9058,dec2virg(luminosity));
      trasp2.backgroundColor=HSBtoRGB(0,0,dec2virg(luminosity));
      }
      return ;
}

function Animate()
{
setInterval("colore()",10);
}

</SCRIPT>
</head>
<body text="#FFFFFF" bgcolor="#FFFFFF" onload="Animate();">
<DIV ID = "trasp" CLASS = "tipo4"><img src="trasp.gif"></DIV>
<DIV ID = "trasp2" CLASS = "tipo5"><img src="trasp.gif"></DIV>
</body>
</html>  
All HLS/HSB values are from 0 to 1.

Hue :
 0.0000 (0/6) = Red
 0.1667 (1/6) = Yellow
 0.3333 (2/6) = Green
 0.5000 (3/6) = Cyan
 0.6667 (4/6) = Blue
 0.8333 (5/6) = Magenta
 1.0000 (6/6) = Red (again)

Your 'yellow' has an orange tinge, because you are using 0.125, instead of 0.16667.

Then, you are ONLY cycling the luminosity. To cycle out from yellow to white, you'd need to 'unsaturate'. Your yellow is 91% saturation.
White is 0% saturation @ 100% Luminance.
Black is any saturation @ 0% Luminance.

If you want to cycle black->yellow-> white, you can :
a) Split the cycle into two parts. Black to Yellow(increasing luminosity), and then Yellow to White(decreasing saturation).
b) decrease the saturation AS you increase the luminance (though you'll never see a bright yellow).

Here's solution a:
--
// Created these vars
var yellow = 1/6; // Hue for Yellow
var ysat   = 1; // 100% saturation
var ylum   = 0; // 0% luminance (black)

var grey   = 0; // Hue for Red
var gsat   = 0; // 0% saturation (white)
var glum   = 0; // 0% luminance (black)

function colore() {
  var isNS = (navigator.appName == "Netscape" && parseInt(navigator.appVersion) >= 4);
  var trasp = (isNS) ? document.trasp : document.all.trasp.style;
  var trasp2 = (isNS) ? document.trasp2 : document.all.trasp2.style;

  // Increase the luminance of the
  // yellow twice as fast as the grey
  ylum += 1
  glum += 0.5

  // When full luminance of the yellow
  // is achieved, unsaturate it (fade to
  // white)
  if( ylum > 100 ) {
   ysat -= 0.01
   ylum = 100;
  }

  // When full luminance of the grey
  // is achieved, reset the cycle.
  if( glum > 100 ) {
    glum = 0;
    ylum = 0;
    ysat = 1;
  }  

  // pure yellow
  var rgb1 = HSBtoRGB( yellow, ysat, dec2virg( ylum ) );
  // 0% saturation = greyscale
  var rgb2 = HSBtoRGB( grey, gsat, dec2virg( glum ) );

  if (isNS) {
    trasp.bgColor = rgb1;
    trasp2.bgColor = rgb2;
  }
  else {
    trasp.backgroundColor = rgb1;
    trasp2.backgroundColor = rgb2;
  }
  return;
}

--

Brian
Avatar of zuppy

ASKER

I'll try tonight....
But...maybe I've made a starting error.
Infact..... now I explain my need.

I must animate a fireplace..... so I must use color piked  randomly for a color and work with it (a different color for every part of fireplace).
For example i must animate fire usig yellow from darker to lighter (yellow-white)....in some point of figure (trasparents).
I started working using RGB but it was so difficult...so, playing with Paintbrush (windows) I noticed that the color change changing Brightness (Luminosity) from 0 to 240.
I thoungt it was simple...a function that convert from HSB to RGB and voila....playing with only a component (B).
I start thinking it is a bad idea.... :(
Hoping you can understand.
Avatar of zuppy

ASKER

I'l put the fireplace somewhere and I'll give the link.... so maybe you can see...what I mean.
Avatar of zuppy

ASKER

NOw here the link

http://www.ilcaminetto.com/mio/cappa13.html

As you can seen (images are not the end one...we ae working on them).... you have 6 lyers:

3 trasparent
3 with object

every trasparent is behind an object...and its background change color

black -> gray for  fireplace backround
(black) ->yellow ->white (should) for fire
orange to dark ornage for the 2 object (I dont kno translation into English)
Hoping you can better understand
I could not find that link

Michel
Avatar of zuppy

ASKER

MMM.....yeah....
Is a strange thing I've just tryed and my DNS tells that it doesn't exist.
Not an nice thing!!
Avatar of zuppy

ASKER

NOw link should be visible (DN guy maked an error, grrrrrrrrrr!!!)
It is up, is the fire supposed to be flickering so much???

Michel
Avatar of zuppy

ASKER

After doing all color setting I'm going to fix it calibrating it.
ASKER CERTIFIED SOLUTION
Avatar of brigmar
brigmar

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of zuppy

ASKER

Thanks for help to everybody, all were interesting answers and I've learned a lot :D
But I must give point to someone....just only one ...so.... but mindlly they are for all.