Font color based on background color

How can I determine if a lighter/darker font color needs to be used based on the background color?

For example, I have a TLabel. If I change the TLabel's color to a darker shade, I want the font color to be white (so the text can be seen). And if I change the TLabel's color to a lighter shade, I want the font color to be black.

I hope I explained it well enough to make sense. :)


Can anyone help me figure this out?
GriegAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

intheCommented:
hi,
you could ave a color that sets the boundaries ,

ie:

to test this try:

procedure TForm1.Button1Click(Sender: TObject);
begin
if label1.Color > clblue then
label1.Font.Color := clwhite else
label1.Font.Color := clblack;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
label1.color := clFuchsia;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
label1.color := clyellow;
end;


clFuchsia is greater than blue so it should change to white here if you click the button and clyellow is les so it would chage it back to white.

i would imagine youll want to fire this on a onpaint or onchange event .
there is probably a better way of doing this but thats all i could think of at moment :)
0
Slick812Commented:
hello Grieg, I tried to use Inverse color font, but for mid grey colors, I could not read the text, I'm not sure about inthe's < clblue value test for color brightness. Here's a sort of less than mid brightness for white version

procedure TForm1.sbut_DoLabelClrClick(Sender: TObject);
var
NewColor, FontColor: TColor;
begin
Randomize;
NewColor := RGB(Random(255),Random(255),Random(255));
{if (GetRValue(NewColor)+GetGValue(NewColor)+ GetBValue(NewColor) > 300) and
   (GetRValue(NewColor)+ GetGValue(NewColor)+ GetBValue(NewColor) < 468) then
   FontColor := clBlack else
FontColor := RGB(255-GetRValue(NewColor), 255-GetGValue(NewColor), 255-GetBValue(NewColor));}
if GetRValue(NewColor)+ GetGValue(NewColor)+ GetBValue(NewColor) < 440 then
FontColor := clWhite
else
FontColor := clBlack;
Label5.Color := NewColor;
Label5.Font.Color := FontColor;
end;

- - - - - - - - - - - - - - - - -
you may could make a testing formula for inverse color but the black and white seem to work for the most part
0
GriegAuthor Commented:
inthe,

The solution doesn't seem to work with non-standard color values. (I tried it with clBlue as the 'boundary color' then chose something a little darker from the windows color dialog.)

I think I failed to mention that I would be working with 'custom' colors from the TColorDialog, and not just the standard 'cl' values.

0
CynnaCommented:
Grieg,

A perfect solution for your problem doesn't exist. What looks good to you doesn't have to feel the same to your customer. This is pretty subjective matter, but you can use reasonably good aproximation, as inthe and Slick suggested.
BUT, if you insist on "close to perfect" solution, you have to make decision based on H,S,L components of the color. The most reasonable solution seems to be using L component (luminiscance), because you are trying to answer question "Is this color dark (enough)?".


Cut&Paste this example:
-----------------------------

procedure RGBtoHSL(RGB: TColor; var 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 := MaxNo (R, MaxNo (G, B));
  Cmin := MinNo (R, MinNo (G, B));
// calculate luminosity
  L := (Cmax + Cmin) / 2;
// if L is all we need, we could Exit now...
  if Cmax = Cmin then  // it's grey
  begin
    H := 0; // it's actually undefined
    S := 0
  end else begin
    D := Cmax - Cmin;
// calculate Saturation
    if L < 0.5 then
      S := D / (Cmax + Cmin)
    else
      S := D / (2 - Cmax - Cmin);
// calculate Hue
    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;

function IsColorDark(Color: TColor; Limit: Integer): Boolean;
// Test luminiscance of the color against specified
// limit (1-100) percentage
var h,s,l: Double;
begin
  // Get Hue,Saturation,and Luminisc. of specified color:
  RGBtoHSL(Color, h, s, l);
  // Use Luminisc. to make decision about dark/light case:
  Result:=Round(l*100)<Limit;
end;

// A little demo (place Panel and ColorDialog on Form)...
procedure TForm1.Panel1Click(Sender: TObject);
var LimitPercent: Integer;
begin
  if ColorDialog1.Execute then
     Panel1.Color:=ColorDialog1.Color;
 
  LimitPercent:=60; // ...can be between 1 and 100
  if IsColorDark(Panel1.Color, LimitPercent) then
     Panel1.Font.Color:=clWhite
  else
     Panel1.Font.Color:=clBlack;
end;




COMMENTS:
-----------

 1. You can adjust "decision level" to value that looks
    best to you (for me, it was 60). Look at the function
    IsColorDark, and you will easily understand.

 2. If you are still not happy, you can base your decision
    not only on L value, but also on H (hue) or even S.

 3. If you are happy with only L value, you can  
    significantly trim this code by excluding H and S
    calculation.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
GriegAuthor Commented:
After trying the proposed solutions I decided to go with Cynna's answer, as using the Luminiscance value seemed to produce the best results for me. Here is what I came up with using a slightly modified version of Cynna's code:


function IsColorDark(AColor: TColor): Boolean
var
 R, G, B, CMax, CMin: Double;
begin
 R := GetRValue(AColor) / 255;
 G := GetGValue(AColor) / 255;
 B := GetBValue(AColor) / 255;
 CMax := MaxNo(R, MaxNo(G, B));
 CMin := MinNo(R, MinNo(G, B));

 // Calculate luminosity and make sure it is less
 // then 50%, or 0.5, indicating a darker color
 Result := ((CMax + CMin) / 2)) < 0.5;
end;



0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Fonts Typography

From novice to tech pro — start learning today.