
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5596 8e941d3f-bd1b-0410-a28a-d453659cc2b4
395 lines
8.5 KiB
ObjectPascal
395 lines
8.5 KiB
ObjectPascal
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.
|