How to calculate the “value” of a background color to know if we should write the text in white or in black on top?
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
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.
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
really I took your solution sascha, the first given
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 !
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.
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!
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.
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.