Something like calculating the average value of rgb components and then decide whether to use black or white?
Do I have to convert RGB to HSV in first step 'cause RGB is not always what the human eyes see?
I'm using C#
Something like calculating the average value of rgb components and then decide whether to use black or white?
Do I have to convert RGB to HSV in first step 'cause RGB is not always what the human eyes see?
I'm using C#
what about that?
private static Color GetReadableForeColor(Color c)
{
return (((c.R + c.B + c.G) / 3) > 128) ? Color.Black : Color.White;
}
It just so happens I needed this function for a project not long ago.
private int PerceivedBrightness(Color c)
{
return (int)Math.Sqrt(
c.R * c.R * .241 +
c.G * c.G * .691 +
c.B * c.B * .068);
}
This formula I found on the web at Nbd Tech that dealt with perceived colors and color conversion formula. The site gives a lot of information that is helpful.
Here's how to use this to select black or white:
var foreColor = (PerceivedBrightness(backColor) > 130 ? Color.Black : Color.White);
You can use a value other than 130 as the cutoff; it is preference.
Update: According to Darel Rex Finley at his site:
The values I came up with by playing with Photoshop were actually .241, .691, and .068, but I have since been informed that the values .299, .587, and .114 are more accurate.
This specification follows ITU-R Recommendation BT.601 (or Rec. 601 for short). The site I mentioned above, Nbd Tech, hasn't yet been updated to reflect this.
Based on this, here is the updated method (thanks to DTI-Matt for the comment):
private int PerceivedBrightness(Color c)
{
return (int)Math.Sqrt(
c.R * c.R * .299 +
c.G * c.G * .587 +
c.B * c.B * .114);
}
Note on threshold preference:
Colors with a perceived brightness near the middle (e.g. 120-140) will be more subjective. For example, it's debatable whether red (FF0000), which evaluates to 139, is clearer with a black or white overlay.
R: .299
G: .587
B: .114
–
Hazeghi Color.Red
(R 255, G 0, B 0), it evaluates to a perceived brightness of 139 based on the values above. I would agree that white-on-red is preferable, but black isn't unreadable. Values in the 120-140 range will be more subjective. Try a threshold of 140 with various colors to see if it suits your purpose. –
Laveralavergne what about that?
private static Color GetReadableForeColor(Color c)
{
return (((c.R + c.B + c.G) / 3) > 128) ? Color.Black : Color.White;
}
The Color
struct supports conversion to HSB natively.
if (Color.GetBrightness() > 0.5f) {
// win
}
You may want to add a component of saturation as well, considering saturation also contributes to apparent 'lightness'.
You could do a simple calculation depending on color depth, if say you had a #FFFFFF color format, you could just add the RGB values and calculate if they're under half way.
The max in that case is 255 (F x F = 256) per, so just check if it's under that threshold:
var colorCode = ((R + B + G) < 255*3) ? "#FFFFFF" : "#000000";
If the color's below, it's darker...use a white background. If it's above, it's lighter...use a black background. It's not perfect, but an idea to get started.
This isn't directly relevant to the question (since it doesn't mention Unity), but for any other readers out there who are using Unity & the UnityEngine.Color
struct, note that they already have a property you can leverage to implement something like this: Color.grayscale
, which returns a float 0-1, similar to the "PerceivedBrightness" function mentioned in the main answer (it uses the same values of r*.299, g*.587, b*.114). It will be closer to 0 for black/dark colors, and closer to 1 for white/bright colors.
Here is the function I'm using with Color.grayscale:
// get most visible color between black & white for a given color (e.g to put text on a color)
public static Color GetReadableForeColor(Color bg) => bg.grayscale > 0.509f ? Color.black : Color.white;
If I'm understanding correctly, one approach might be to get hold of the desktop wallpaper image, check in some manor what colour it is and then change your application colour based on that.
There's an article on geekpedia about getting hold of the current desktop wallpaper (and lots of hits on google on that), but the basic premise is to grab the registry value of the current wallpaper:
RegistryKey rkWallPaper = Registry.CurrentUser.OpenSubKey("Control Panel\\Desktop", false);
string WallpaperPath = rkWallPaper.GetValue("WallPaper").ToString();
You could then use that path to open the image. You can then get hold of lots of properties, such as the dimensions and individual pixel colours in RGB.
To work out whether it's "more white" or "more black" you have many options.
One idea would be to get each pixel colour in RGB, average the values (to get the greyscale value) and then average the greyscale value of each pixel across the image. If this comes out > 128 then it could be condidered to be "white". If < 128 then "black". Basically you are deciding which side of the mid-grey dividing line the images pixel intensities average out to.
// Psudo code - can't check the C# spec atm.
foreach(Pixel p in image)
{
// get average of colour components.
double greyScale = (p.Red + p.Green + p.Blue) / 3;
totalIntensity += greyScale;
}
double averageImageIntensity = totalIntensity / image.NumPixels;
if(totalIntensity > 128) // image could be considered to be "white"
else // image could be considered "black".
Problems: could be a slow procedure, you might want to sample only some of the pixels (say, every 10th one etc.) to save time. More generally, it seems like a fairly hacky thing to be doing at all. Pulling user files at run-time and messing with them is hardly clean, and it provides potential security and stability concerns. What if the image is duff or corrupt etc.
Personally I'd suggest simply giving the user the choice of colour / theme / skin themselves, or better yet let them customise it!
© 2022 - 2024 — McMap. All rights reserved.