I think this is a question about numeric programming

and not so much about colors:

I want to be able to convert Red, Green and Blue

(each having a value from 0 to 255) to

Hue, Saturation and Luminance (the HSL/HSB model),

(each having a value from 0 to 240), and back.

The delphi (WINAPI) help has the C code for this

(search help on RGBtoHSL).

I tried to port this C code to Delphi. It worked

for most cases but sometimes there is a slight difference

(roundoff error).

I mean: when I put use RGBtoHSL on some legal RGB values

and convert it back with HSLtoRGB the RGB values in rare

cases are slighty different (e.g. R=R, G=G+1, B=B-1).

First, I used TRUNC() for the real to integer conversions,

and then I only used reals instead of integers and

rounded off later. The result is about the same, the

latter being a little worse.

Has any one ported this functions such that you

can convert back and forth as many times as you please

without this slight differences?

To be explicit suppose R=x, G=y, B=z

I want to be able to call RGBtoHSL and then HSLtoRGB and repeat this process a 1000 times,

and still the result must be R=x, G=y and B=z.

Please give the code.

and not so much about colors:

I want to be able to convert Red, Green and Blue

(each having a value from 0 to 255) to

Hue, Saturation and Luminance (the HSL/HSB model),

(each having a value from 0 to 240), and back.

The delphi (WINAPI) help has the C code for this

(search help on RGBtoHSL).

I tried to port this C code to Delphi. It worked

for most cases but sometimes there is a slight difference

(roundoff error).

I mean: when I put use RGBtoHSL on some legal RGB values

and convert it back with HSLtoRGB the RGB values in rare

cases are slighty different (e.g. R=R, G=G+1, B=B-1).

First, I used TRUNC() for the real to integer conversions,

and then I only used reals instead of integers and

rounded off later. The result is about the same, the

latter being a little worse.

Has any one ported this functions such that you

can convert back and forth as many times as you please

without this slight differences?

To be explicit suppose R=x, G=y, B=z

I want to be able to call RGBtoHSL and then HSLtoRGB and repeat this process a 1000 times,

and still the result must be R=x, G=y and B=z.

Please give the code.

The functions which I have written for the conversions are :

procedure HSLtoRGB(H,S,L:Integer;var

var

Sat,Lum : Double;

begin

R := 0;

G := 0;

B := 0;

if (H < 360) and (H >= 0) and (S <= 100) and (S >= 0) and (L <= 100) and (L >= 0) then begin

if H <=60 then begin

R := 255;

G := Round((255/60)*H);

B := 0;

end

else if H <=120 then begin

R := Round(255-(255/60)*(H-60))

G := 255;

B := 0;

end

else if H <=180 then begin

R := 0;

G := 255;

B := Round((255/60)*(H-120));

end

else if H <=240 then begin

R := 0;

G := Round(255-(255/60)*(H-180)

B := 255;

end

else if H <=300 then begin

R := Round((255/60)*(H-240));

G := 0;

B := 255;

end

else if H <360 then begin

R := 255;

G := 0;

B := Round(255-(255/60)*(H-300)

end;

Sat := Abs((S-100)/100);

R := Round(R-((R-128)*Sat));

G := Round(G-((G-128)*Sat));

B := Round(B-((B-128)*Sat));

Lum := (L-50)/50;

if Lum > 0 then begin

R := Round(R+((255-R)*Lum));

G := Round(G+((255-G)*Lum));

B := Round(B+((255-B)*Lum));

end

else if Lum < 0 then begin

R := Round(R+(R*Lum));

G := Round(G+(G*Lum));

B := Round(B+(B*Lum));

end;

end;

end;

procedure RGBtoHSL(R,G,B:Integer;var

var

Delta : Double;

CMax,CMin : Double;

Red,Green,Blue,Hue,Sat,Lum

begin

Red := R/255;

Green := G/255;

Blue := B/255;

CMax := Max(Red,Max(Green,Blue));

CMin := Min(Red,Min(Green,Blue));

Lum := (CMax+CMin)/2;

if CMax = CMin then begin

Sat := 0;

Hue := 0;

end

else begin

if Lum < 0.5 then Sat := (CMax-CMin)/(CMax+CMin)

else Sat := (cmax-cmin)/(2-cmax-cmin);

delta := CMax-CMin;

If Red = CMax then Hue := (Green-Blue)/Delta

else if Green = CMax then Hue := 2+(Blue-Red)/Delta

else Hue := 4.0+(Red-Green)/Delta;

Hue := Hue / 6;

If Hue < 0 then Hue := Hue + 1;

end;

H := Round(Hue*360);

S := Round(Sat*100);

L := Round(Lum*100);

end;

function Max(a,b:Double):Double;

begin

if a > b then result := a

else result := b;

end;

function Min(a,b:Double):Double;

begin

if a < b then result := a

else result := b;

end;

You should have little difficulty converting these to work with real numbers should you wish. The HSL values are also in a different range to the ones you specify, however this is also pretty simple to rectify. I hope this goes some way towards solving your problem, however it is implicitly impossible to completely solve the problem, for the reasons which I suggest.

Steven.

Try define HSL as (56,134,120) - You can't You'r values will be changed to (56,135,120).

answer = for some integer values of RGB exist more than 1 integer values of HSL and vice versa. If you need call this function 1000 times you need store values in real numbers.

2. Yes i wrote so proc from Steven can be better.

3. I will try resolve this problem with any solution - wait.

Sorry for my english.

I just read "Introduction To Computer Graphics" of James D.Foley and ...

I found so you'r problem is not numeric programming.

You can't convert RGB to HSL in all cases ! It is imposiible in theory !

Answer = if You use real numbers the problem is the same. You can convert uniformly RGB to CMYK but not RGB to HSL.

p.s. Do You know so some colors is inacessible with RGB ? (some colors don't have RGB representation).

Example:

HSB2RGB[240] would return 255

Create the RGB2HSB array by picking the cell index of the closest match in HSB2RGB.

Hope it can help.

KE has an interesting solution, however it's still not perfect. Your arrays would obviously have to be 3 dimensional : (eg RGB2HSL[r,g,b]) and the result would be at least a 24 bit number to hold the three 8 bit values. However as there are different numbers of enties in each of your colour models (240^3 for HSL and 255^3 for RGB) the translation would not be exact even with this solution.

The answer still stands, that the problem CANNOT be completely solved, especially towards the extremes of the luminance range. This has however piqued my interest, so I'll keep looking at it when I have the time.

Steven.

The only problem to this solution is to calculate the arrays correct. I shouldn't have called the arrays HSB2RGB in my previous answer, when it's not what it actually does. It only converts between range 240 to range 255.

1.We have two sets of values A-with values for RGB and B-with values for HSV.

2.For two integer values of A exist one corresponding value of B.

3 If you put to conversion one of this not uniform values then when you made reconversion you can't get correct values. For Example A1 and A2 have the same B1. When you made conversion of A1 you get B1 and When you made reconversion you can get A1, but if You put A2 to conversion you get B1 and after reconversion you get A1 not A2. This is the reason why this is impossible.

3. I made small mistake with my previous comment - in real values you can do conversion and reconversion but any rounding make this problem impossible, because the confersion is not afinity conversion.

4.I have now small algorithm "from book of graphics" for real numbers and i go to test this problem in real numbers.

5. Mayby you can solve the problem in different way

6.Sorry for my english.

There exist two singularities in the RGB color map (Black and White) that map to an infinite number of points in the HSL color map (Lum = Min and Max respectivly). As you approach these points in RGB space, the precision of your HSL storage becomes more and more significant, until it spirals off into infinity, never to be reconverted.

Steven.

I wrote the example later. (56,134,120 and 56,135,120) have the same RGB.

It is possibble only to made algorithm which sometimes after first conversion give you difference by 1 and all next conversion without differences.

My english is poor and i think so you don't fully understand my previous comment. Here is example :

HSLtoRGB( 56,134,120)=(142,200,55)

RGBtoHSL( 142,200,55)=( 56,134,120)

but what when you put 56,135,120 ?

HSLtoRGB( 56,135,120 = (142,200,55)

RGBtoHSL( 142,200,55)=(56,134,120) !!!!!!!!!!!!!!!!!

The conversion in integer numbers is NOT UNIFORM and you can't construct good for you allgorithm.

Miauw, Sorry we couldn't completely solve your problem. I'm glad to hear that you've found a practical solution. If you want to assign the points, then I'll be happy to accept them.

This has been an interesting discussion, if anyone comes up with anything new, then keep posting it here, or mail it to me:

stemail@dial.pipex.com

Steven.

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the ExpertsCreate a free account to continue.

Limited access with a free account allows you to:

- View three pieces of content (articles, solutions, posts, and videos)
- Ask the experts questions (counted toward content limit)
- Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.