Reverse opposing colors
Solution 1
I found that the best solution for me is to convert the RGB values into YIQ values. As we are only interested in the brightness value (represented by Y), there is one single calculation to be done: Y = (299*R + 587*G + 114*B)/1000
. The Java code for that would look like this:
public static Color getContrastColor(Color color) {
double y = (299 * color.getRed() + 587 * color.getGreen() + 114 * color.getBlue()) / 1000;
return y >= 128 ? Color.black : Color.white;
}
You can see that it simply decides to use black or white, based upon the brightness of the original color. And the result works very nice in my opinion. The weights (299, 587, 114) are proportional to the sensitivity of the eyes (or rather the sensitivity of the retina) to the corresponding color.
Solution 2
Use complementary color:
Algo is simple, substract each color component from 255 to get new color components
Color textColor = Color.rgb(255-Color.red(bgColor),
255-Color.green(bgColor),
255-Color.blue(bgColor));
----- EDIT (As RGB based complement may not work always --------
These two links are very much helpful and on topic:
http://www.splitbrain.org/blog/2008-09/18-calculating_color_contrast_with_php
http://24ways.org/2010/calculating-color-contrast
Solution 3
Based on Marks solution I would suggest:
public static int getComplementaryColor(int colorToInvert) {
float[] hsv = new float[3];
Color.RGBToHSV(Color.red(colorToInvert), Color.green(colorToInvert),
Color.blue(colorToInvert), hsv);
hsv[0] = (hsv[0] + 180) % 360;
return Color.HSVToColor(hsv);
}
And additionally I now created a similar method, for calculating a default background for a given color:
public static int getContrastVersionForColor(int color) {
float[] hsv = new float[3];
Color.RGBToHSV(Color.red(color), Color.green(color), Color.blue(color),
hsv);
if (hsv[2] < 0.5) {
hsv[2] = 0.7f;
} else {
hsv[2] = 0.3f;
}
hsv[1] = hsv[1] * 0.2f;
return Color.HSVToColor(hsv);
}
Solution 4
As Sarwar Erfan pointed out, use complementary colors. For that, you can use an integer mask (which will be faster, than inverting R, G, B color components separately).
int textColor = bgColor ^ 0x00ffffff;
Solution 5
integer solution:
public static int getContrastColor(int color) {
double y = (299 * Color.red(color) + 587 * Color.green(color) + 114 * Color.blue(color)) / 1000;
return y >= 128 ? Color.BLACK : Color.WHITE;
}
Related videos on Youtube
Mark Worsnop
Updated on July 09, 2022Comments
-
Mark Worsnop almost 2 years
I have a user setup where they can choose the colors of the alerts. the Alert is the background color on a text or button. But the problem comes in that if they select a dark blue and we have black letters the contrast isnt enough and you cannot read it.
I have tried to make a function to get the reverse opposing color but havent got too far.
Is there such a function?
-
Nemi over 13 yearsThere are at least two questions on here for this. One is stackoverflow.com/questions/596216/…. I know because I implemented an algorithm from one of them and it works well.
-
-
Anthony over 13 yearsDoesn't this give a big issue when the user selects the color 128/128/128 (or something really near).
-
Sarwar Erfan over 13 yearsI have included a link from Wikipedia in the answer. RGB based complement is easiest to understand. HSV based complement will work in this case. @Shynhriir: Yes.. RGB based complement will not work in this range, you are absolutely right
-
Mark Worsnop over 13 yearsHow would you code into Android the complementary color from the Wiki link?
-
Sarwar Erfan over 13 years@Mark: It is not very hard. I have previously wrote my own 3d perspective transformation code just reading the corresponding theories.
-
Mark Worsnop over 13 yearsIf you are new to Java and Android it is :) I got it though... see above
-
Sarwar Erfan over 13 years@Mark: You have future I see.
-
Hoang Tran almost 11 yearsThanks. This may not cover all cases, but is pefect for my usecase (make text readable on colored background)
-
brimborium almost 11 yearsYou always can read the text pretty good. The disadvantage is, that the text will be black or white, color information of the background is "lost".
-
Simon over 9 yearswhy that "RGBMAX - "? and the hue is a value between 0 and 360 and not 0 and 1 I think, i postet an updated version below
-
Shajeel Afzal over 8 yearsYou
getComplementaryColor
is working perfectly but notgetContrastVersionForColor
can you please fix? -
Simon over 8 yearsWhat do you mean it does not work? You don't like the result? Can you provide a color int value for which it does not look right? I use it quite often and never had problems
-
Phani over 8 yearsCan you please explain on how it would solve the problem ?
-
Eboo over 8 years"I have tried to make a function to get the reverse opposing color but havent got too far. " So here is a function ^^ it return black or white color.
-
Phani over 8 yearsGoing back to first question..if it doesn't resolve the issue..then delete it.. or else update the question with latest findings.
-
Emmanuel Istace almost 6 yearsOMFG, I have been messing with RGB/HSV conversion and hue shifting for hours without "nice" sucess and this is by far the best and so easy solution I've found for my need. Thanks.
-
brimborium over 5 yearsI like this solution a lot. A perfect alternative if you don't like the black/white YIQ approach.
-
Frontear almost 5 years@brimborium has already posted an extremely similar response 3 years before yours.
-
Mustafa almost 4 yearsIn JavaFx the value y will be between 0 and 1. So the last line of this method should look like this
return y >= 0.5 ? Color.valueOf("#000000") : Color.valueOf("#ffffff");
-
ZaFaR97 about 2 yearsTo make it works on Android apps, I edit it: ``` private int getContrastColor(int color) { double y = (299 * Color.red(color) + 587 * Color.green(color) + 114 * Color.blue(color)) / 1000; return y >= 128 ? Color.BLACK : Color.WHITE; }```