Solved

Font color based on background color

Posted on 2002-06-04
5
875 Views
Last Modified: 2013-12-03
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?
0
Comment
Question by:Grieg
5 Comments
 
LVL 17

Expert Comment

by:inthe
ID: 7054847
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
 
LVL 33

Expert Comment

by:Slick812
ID: 7054938
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
 

Author Comment

by:Grieg
ID: 7054962
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
 
LVL 7

Accepted Solution

by:
Cynna earned 100 total points
ID: 7055848
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
 

Author Comment

by:Grieg
ID: 7056903
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

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now