unit RGBHSLUtils; {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} interface uses LCLIntf, LCLType, Graphics, Math, Scanlines; var //set these variables to your needs, e.g. 360, 255, 255 MaxHue: integer = 359; MaxSat: integer = 240; MaxLum: integer = 240; {function HSLtoRGB(H, S, L: double): TColor;} function HSLRangeToRGB(H, S, L: integer): TColor; {procedure ColorToHSL(AColor: TColor; var H, S, L: Double);} function HSLtoColor(H, S, L: Double): TColor; {procedure RGBtoHSL(RGB: TColor; out H, S, L: Double); } procedure RGBtoHSLRange(RGB: TColor; out H1, S1, L1: integer); function GetHValue(AColor: TColor): integer; function GetSValue(AColor: TColor): integer; function GetLValue(AColor: TColor): integer; function HSLToRGBTriple(H, S, L : integer) : TRGBTriple; function HSLToRGBQuad(H, S, L: integer): TRGBQuad; procedure RGBTripleToHSL(RGBTriple : TRGBTriple; var h, s, l: integer); implementation uses mbUtils; (* procedure ColorToHSL(AColor: TColor; var H, S, L: Double); function RGBMaxValue(r, g, b: Double): Double; begin Result := r; if (Result < g) then Result := g; if (Result < b) then Result := b; end; function RGBMinValue(r, g, b: Double): Double; begin Result := r; if (Result > g) then Result := g; if (Result > b) then Result := b; end; var r, g, b: Double; delta, min: Double; begin r := GetRValue(AColor)/255; g := GetGValue(AColor)/255; b := GetBValue(AColor)/255; L := RGBMaxValue(r, g, b); min := RGBMinValue(r, g, b); delta := L - min; if (L = min) then begin H := 0.0; S := 0.0; end else begin S := delta / L; if r = L then H := 60 * (g - b)/delta else if g = L then H := 60 * (b - r)/delta + 120 else if b = L then H := 60 * (r - g)/delta + 240; if H < 0 then H := H + 360; H := H / 360; end; end; *) function HSLtoColor(H, S, L: Double): TColor; const Divisor = 255*60; var hTemp, f, LS, p, q, r: integer; intH, intS, intL: Integer; begin intH := round(H*360); intS := round(S*255); intL := round(L*255); if intH > 360 then dec(intH, 360); if intH < 0 then inc(intH, 360); Clamp(intS, 0, 255); Clamp(intL, 0, 255); if (intS = 0) then Result := RGBtoColor(intL, intL, intL) else begin hTemp := intH mod 360; f := hTemp mod 60; hTemp := hTemp div 60; LS := intL * intS; p := intL - LS div 255; q := intL - (LS*f) div Divisor; r := intL - (LS*(60 - f)) div Divisor; case hTemp of 0: Result := RGBtoColor(intL, r, p); 1: Result := RGBtoColor(q, intL, p); 2: Result := RGBtoColor(p, intL, r); 3: Result := RGBtoColor(p, q, intL); 4: Result := RGBtoColor(r, p, intL); 5: Result := RGBtoColor(intL, p, q); else Result := RGBtoColor(0, 0, 0); end; end; end; // ============================================================================= function HSLtoRGB(H, S, L: double): TColor; var M1, M2: double; function HueToColorValue(Hue: double): byte; var V : double; begin if Hue > 10 then Hue := Hue + 1; if Hue < 0 then Hue := Hue + 1 else if Hue > 1 then Hue := Hue - 1; if 6 * Hue < 1 then V := M1 + (M2 - M1) * Hue * 6 else if 2 * Hue < 1 then V := M2 else if 3 * Hue < 2 then V := M1 + (M2 - M1) * (2/3 - Hue) * 6 else V := M1; Result := round(255 * V) end; var R, G, B: byte; begin if S = 0 then begin R := round(255 * L); G := R; B := R end else begin if L <= 0.5 then M2 := L * (1 + S) else M2 := L + S - L * S; M1 := 2 * L - M2; R := HueToColorValue(H + 1/3); G := HueToColorValue(H); B := HueToColorValue(H - 1/3) end; Result := RGB(R, G, B) end; function HSLRangeToRGB(H, S, L: integer): TColor; begin Clamp(H, 0, MaxHue); Clamp(S, 0, MaxSat); Clamp(L, 0, MaxLum); Result := HSLToRGB(H / MaxHue, S / MaxSat, L / MaxLum); end; //============================================================================== procedure RGBtoHSL(RGB: TColor; out H, S, L: Double); var R, G, B, D, Cmax, Cmin: double; begin R := GetRValue(RGB) / 255; G := GetGValue(RGB) / 255; B := GetBValue(RGB) / 255; Cmax := Max(R, Max(G, B)); Cmin := Min(R, Min(G, B)); L := (Cmax + Cmin) / 2; if Cmax = Cmin then begin H := 0; S := 0; end else begin D := Cmax - Cmin; //calc S if L < 0.5 then S := D / (Cmax + Cmin) else S := D / (2 - Cmax - Cmin); //calc H if R = Cmax then H := (G - B) / D else if G = Cmax then H := 2 + (B - R) /D else H := 4 + (R - G) / D; H := H / 6; if H < 0 then H := H + 1; end; end; procedure RGBtoHSLRange(RGB: TColor; out H1, S1, L1: integer); var R, G, B, D, Cmax, Cmin, h, s, l: double; begin R := GetRValue(RGB) / 255; G := GetGValue(RGB) / 255; B := GetBValue(RGB) / 255; Cmax := Max(R, Max (G, B)); Cmin := Min(R, Min (G, B)); L := (Cmax + Cmin) / 2; if Cmax = Cmin then begin H := 0; S := 0; end else begin D := Cmax - Cmin; //calc L if L < 0.5 then S := D / (Cmax + Cmin) else S := D / (2 - Cmax - Cmin); //calc H if R = Cmax then H := (G - B) / D else if G = Cmax then H := 2 + (B - R) /D else H := 4 + (R - G) / D; H := H / 6; if H < 0 then H := H + 1; end; H1 := round(H * MaxHue); S1 := round(S * MaxSat); L1 := round(L * MaxLum); end; // ============================================================================= function GetHValue(AColor: TColor): integer; var d, h: integer; begin RGBToHSLRange(AColor, h, d, d); Result := h; end; function GetSValue(AColor: TColor): integer; var d, s: integer; begin RGBToHSLRange(AColor, d, s, d); Result := s; end; function GetLValue(AColor: TColor): integer; var d, l: integer; begin RGBToHSLRange(AColor, d, d, l); Result := l; end; function HSLToRGBTriple(H, S, L: integer): TRGBTriple; const Divisor = 255*60; var hTemp, f, LS, p, q, r: integer; begin Clamp(H, 0, MaxHue); Clamp(S, 0, MaxSat); Clamp(L, 0, MaxLum); if (S = 0) then Result := RGBToRGBTriple(L, L, L) else begin hTemp := H mod MaxHue; f := hTemp mod 60; hTemp := hTemp div 60; LS := L*S; p := L - LS div MaxLum; q := L - (LS*f) div Divisor; r := L - (LS*(60 - f)) div Divisor; case hTemp of 0: Result := RGBToRGBTriple(L, r, p); 1: Result := RGBToRGBTriple(q, L, p); 2: Result := RGBToRGBTriple(p, L, r); 3: Result := RGBToRGBTriple(p, q, L); 4: Result := RGBToRGBTriple(r, p, L); 5: Result := RGBToRGBTriple(L, p, q); else Result := RGBToRGBTriple(0, 0, 0); end; end; end; function HSLToRGBQuad(H, S, L: integer): TRGBQuad; const Divisor = 255*60; var hTemp, f, LS, p, q, r: integer; begin Clamp(H, 0, MaxHue); Clamp(S, 0, MaxSat); Clamp(L, 0, MaxLum); if (S = 0) then Result := RGBToRGBQuad(L, L, L) else begin hTemp := H mod MaxHue; f := hTemp mod 60; hTemp := hTemp div 60; LS := L*S; p := L - LS div MaxLum; q := L - (LS*f) div Divisor; r := L - (LS*(60 - f)) div Divisor; case hTemp of 0: Result := RGBToRGBQuad(L, r, p); 1: Result := RGBToRGBQuad(q, L, p); 2: Result := RGBToRGBQuad(p, L, r); 3: Result := RGBToRGBQuad(p, q, L); 4: Result := RGBToRGBQuad(r, p, L); 5: Result := RGBToRGBQuad(L, p, q); else Result := RGBToRGBQuad(0, 0, 0); end; end; end; procedure RGBTripleToHSL(RGBTriple: TRGBTriple; var h, s, l: integer); function RGBMaxValue(RGB: TRGBTriple): byte; begin Result := RGB.rgbtRed; if (Result < RGB.rgbtGreen) then Result := RGB.rgbtGreen; if (Result < RGB.rgbtBlue) then Result := RGB.rgbtBlue; end; function RGBMinValue(RGB: TRGBTriple) : byte; begin Result := RGB.rgbtRed; if (Result > RGB.rgbtGreen) then Result := RGB.rgbtGreen; if (Result > RGB.rgbtBlue) then Result := RGB.rgbtBlue; end; var Delta, Min: byte; begin L := RGBMaxValue(RGBTriple); Min := RGBMinValue(RGBTriple); Delta := L-Min; if (L = Min) then begin H := 0; S := 0; end else begin S := MulDiv(Delta, 255, L); with RGBTriple do begin if (rgbtRed = L) then H := MulDiv(60, rgbtGreen-rgbtBlue, Delta) else if (rgbtGreen = L) then H := MulDiv(60, rgbtBlue-rgbtRed, Delta) + 120 else if (rgbtBlue = L) then H := MulDiv(60, rgbtRed-rgbtGreen, Delta) + 240; if (H < 0) then H := H + 360; end; end; end; end.