I need to make color of my Status Bar (it is a TPanel
) change (Lighten or Darken) automatically according to user's current System Specifications which is displayed in my wpInfoBefore
Wizard Page.
I like to have two functions which can do this correctly by inputting a TColor
as Value. But , I tried many times to write those functions by reading posts like this , even using RGB
function, but with no success.
For Example, If I need to darken or lighten the given TColor
, I may need to use functions like shown below:
var
RecommendedStatusColor: TColor;
function LightenColor(Colour: TColor, Percentage: Integer): TColor;
begin
...
end;
function DarkenColor(Colour: TColor, Percentage: Integer): TColor;
begin
...
end;
RecommendedStatusColor := $00D000;
if ... then
StatusBar.Color := LightenColor(RecommendedStatusColor, 75);
//Lighten given color by 75%
if ... then
StatusBar.Color := DarkenColor(RecommendedStatusColor, 50);
//Darken given color by 50%
Output should be the modified (Lightened or Darkened) TColor.
Thanks in Advance.
You have to convert the color to HSL or HSV and change the lightness (L) or value (V) and convert back to RGB.
The following code uses the HSL (L = lightness).
function GetRValue(RGB: Cardinal): Byte;
begin
Result := Byte(rgb);
end;
function GetGValue(RGB: Cardinal): Byte;
begin
Result := Byte(rgb shr 8);
end;
function GetBValue(RGB: Cardinal): Byte;
begin
Result := Byte(rgb shr 16);
end;
function Max(A, B: Integer): Integer;
begin
if A > B then
Result := A
else
Result := B;
end;
function Min(A, B: Integer): Integer;
begin
if A < B then
Result := A
else
Result := B;
end;
const
HLSMAX = 240;
RGBMAX = 255;
HLSUndefined = (HLSMAX*2/3);
procedure ColorRGBToHLS(RGB: Cardinal; var Hue, Luminance, Saturation: Word);
var
H, L, S: Double;
R, G, B: Word;
cMax, cMin: Double;
Rdelta, Gdelta, Bdelta: Word; // intermediate value: % of spread from max
begin
R := GetRValue(RGB);
G := GetGValue(RGB);
B := GetBValue(RGB);
// calculate lightness
cMax := Max(Max(R, G), B);
cMin := Min(Min(R, G), B);
L := ( ((cMax + cMin) * HLSMAX) + RGBMAX ) / ( 2 * RGBMAX);
Luminance := Trunc(L);
if cMax = cMin then // r=g=b --> achromatic case
begin
Hue := Trunc(HLSUndefined);
Saturation := 0;
end
else // chromatic case
begin
// saturation
if Luminance <= HLSMAX/2 then
begin
S := ( ((cMax-cMin)*HLSMAX) + ((cMax+cMin)/2) ) / (cMax+cMin);
end
else
begin
S := ( ((cMax-cMin)*HLSMAX) + ((2*RGBMAX-cMax-cMin)/2) ) /
(2*RGBMAX-cMax-cMin);
end;
// hue
Rdelta := Trunc(( ((cMax-R)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin));
Gdelta := Trunc(( ((cMax-G)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin));
Bdelta := Trunc(( ((cMax-B)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin));
if (Double(R) = cMax) then
begin
H := Bdelta - Gdelta
end
else if (Double(G) = cMax) then
begin
H := (HLSMAX/3) + Rdelta - Bdelta
end
else // B == cMax
begin
H := ((2 * HLSMAX) / 3) + Gdelta - Rdelta;
end;
if (H < 0) then
H := H + HLSMAX;
if (H > HLSMAX) then
H := H - HLSMAX;
Hue := Round(H);
Saturation := Trunc(S);
end;
end;
function HueToRGB(Lum, Sat, Hue: Double): Integer;
var
ResultEx: Double;
begin
// range check: note values passed add/subtract thirds of range
if (hue < 0) then
hue := hue + HLSMAX;
if (hue > HLSMAX) then
hue := hue - HLSMAX;
// return r,g, or b value from this tridrant
if (hue < (HLSMAX/6)) then
ResultEx := Lum + (((Sat-Lum)*hue+(HLSMAX/12))/(HLSMAX/6))
else if (hue < (HLSMAX/2)) then
ResultEx := Sat
else if (hue < ((HLSMAX*2)/3)) then
ResultEx := Lum + (((Sat-Lum)*(((HLSMAX*2)/3)-hue)+(HLSMAX/12))/(HLSMAX/6))
else
ResultEx := Lum;
Result := Round(ResultEx);
end;
function RoundColor(Value: Double): Integer;
begin
if Value > 255 then
Result := 255
else
Result := Round(Value);
end;
function RGB(R, G, B: Byte): Cardinal;
begin
Result := (Cardinal(R) or (Cardinal(G) shl 8) or (Cardinal(B) shl 16));
end;
function ColorHLSToRGB(Hue, Luminance, Saturation: Word): Cardinal;
var
R, G, B: Double; // RGB component values
Magic1, Magic2: Double; // calculated magic numbers (really!)
begin
if (Saturation = 0) then
begin // achromatic case
R := (Luminance * RGBMAX)/HLSMAX;
G := R;
B := R;
if (Hue <> HLSUndefined) then
; // ERROR
end
else
begin // chromatic case
// set up magic numbers
if (Luminance <= (HLSMAX/2)) then
begin
Magic2 := (Luminance * (HLSMAX + Saturation) + (HLSMAX/2)) / HLSMAX;
end
else
begin
Magic2 :=
Luminance + Saturation - ((Luminance * Saturation) +
(HLSMAX/2)) / HLSMAX;
end;
Magic1 := 2 * Luminance - Magic2;
// get RGB, change units from HLSMAX to RGBMAX
R := (HueToRGB(Magic1,Magic2,Hue+(HLSMAX/3))*RGBMAX + (HLSMAX/2))/HLSMAX;
G := (HueToRGB(Magic1,Magic2,Hue)*RGBMAX + (HLSMAX/2)) / HLSMAX;
B := (HueToRGB(Magic1,Magic2,Hue-(HLSMAX/3))*RGBMAX + (HLSMAX/2))/HLSMAX;
end;
Result := RGB(RoundColor(R), RoundColor(G), RoundColor(B));
end;
function LightenColor(RGB: Cardinal; Percentage: Integer): Cardinal;
var
H, S, L: Word;
begin
ColorRGBToHLS(RGB, H, L, S);
L := (Cardinal(L) * Percentage) div 100;
Result := ColorHLSToRGB(H, L, S);
end;
function GetSysColor(nIndex: Integer): DWORD;
external '[email protected] stdcall';
function ColorToRGB(Color: TColor): Cardinal;
begin
if Color < 0 then
Result := GetSysColor(Color and $000000FF) else
Result := Color;
end;
Usage:
LighterColor := TColor(LightenColor(ColorToRGB(Color), 150));
DarkerColor := TColor(LightenColor(ColorToRGB(Color), 75));
References:
ColorRGBToHLS
+ ColorHLSToRGB
– VCL source codeMin
+ Max
– Inno Setup get Min and Max Integer values in Pascal ScriptColorToRGB
– Converting Inno Setup WizardForm.Color to RGBLightenColor
– Lighten colors programmatically with Delphi