# Text color question

How to calculate the “value” of a background color to know if we should write the text in white or in black on top?

1 Like

thank you Sascha, but in xojo, we already have the Hue of the color
I wonder how to calculate the threshold that makes the eye see better when it’s written in black or white over a background of this color

``````Public Function ContrastColor(BackgroundColor As Color) As Color
Var c As Integer
Var luminance As Double

luminance = (0.299 * BackgroundColor.Red + 0.587 * BackgroundColor.Green + 0.114 * BackgroundColor.Blue)/255

If luminance > 0.5 Then
c = 0 // bright colors - black font
Else
c = 255 // dark colors - white font
End If

Return  Color.RGB(c,c,c)
End Function
``````

An Example:

2 Likes

You can make the color calculation faster by using this code

``````Public Function ContrastColor(BackgroundColor As Color) As Color
Var luminance As Integer = 0.299 * BackgroundColor.Red + 0.587 * BackgroundColor.Green + 0.114 * BackgroundColor.Blue
If luminance > 127 Then
Return  Color.Black
Else
Return  Color.White
End If
End Function
``````

Less calculation and no Color.RGB() call for the returned color.

3 Likes

yes, that’s right, thank you!

I give a solution and @TomE1 TomE tunes it for speed = TomE provides the solution. Now i’m sad

No just joking. Glad i could help

1 Like

really I took your solution sascha, the first given

1 Like

Now @TomE1 may be sad Because speed is really important when it comes to graphics, Tom‘s updated solution may be the „better“ one.

Thanks to TomE too !

1 Like

Perhaps there is even a better solution. Use inline if.
Here is my sample code from a button and a TextField “out” in a window.

``````#Pragma BackgroundTasks false

var d as double
const loopMax = 1000000
var c As Color = Color.Red
var result As Color

d = System.Microseconds
for i as integer = 1 to loopMax
result = ContrastColor(Color.Red)
Next
d = (System.Microseconds - d) / 1000
out.AddText "ContrastColor: "+ str(d) + " ms" + EndOfLine

d = System.Microseconds
for i as integer = 1 to loopMax
result = ContrastColorFast(c)
Next
d = (System.Microseconds - d) / 1000
out.AddText "ContrastColorFast: "+ str(d) + " ms" + EndOfLine

d = System.Microseconds
for i as integer = 1 to loopMax
result = if(0.299 * c.Red + 0.587 * c.Green + 0.114 * c.Blue > 127, Color.Black, Color.White)
Next
d = (System.Microseconds - d) / 1000
out.AddText "ContrastColor inline: "+ str(d) + " ms" + EndOfLine
``````

And this is the result:

ContrastColor: 765.8987 ms
ContrastColorFast: 595.8415 ms
ContrastColor inline: 97.60887 ms

I think it makes sense to use inline code within a paint event.

1 Like

From experience for stuff very like this, I should say ‘it depends’
If this occurs once in the paint event , it probably makes no difference.

But (as I found out from a change made to DynaPDFMBS) , even a tiny change to a function can make a big difference if repeated thousands of times.

HERE, my question is ‘how many different colors can there be to draw text over’?
Given the size of the screen and the size of words, I would be surprised if there were more than a few hundred.
(There are 216 web safe colors for example)

If that is the case, like many things that can be repeated a lot, pre-calculation is your friend.
Create a dictionary where each of the 216 colors is the key, and the value is the correct text color.
Then, getting the text color from the dictionary when it is needed will be faster than even the inline code if called thousands of times.

(In the test above, the inline code uses the same color and values in each pass. It may even be that the compiler optimised that method if it was smart enough)

I understand, Jeff, but in this app the user can choose any color, so the dictionary solution is not valid: but I retain the idea!

1 Like

Hi guys,
if you want to see a preview of black or white text on a given background color, check out https://www.0to255.com/
Greetings to all

If you’re a GraffitiSuite Desktop customer, I have this (Complement and ComplementReadable) and a bunch of other color functions in GraffitiColors.

2 Likes

Of course if you calculate it a million times. But I totally disagree if you need it for a few rects in a single paint loop.