Reputation: 3291
as per title, my question is: Does Android provide any way to analyze/determine if a color (that will be obviously dynamic for the purpose) is light or dark?
Upvotes: 70
Views: 27358
Reputation: 30645
In Kotlin using extension function on Int
type and with a darkness threshold
parameter it can look like the following:
/**
* Determines if this color is dark.
* @param threshold - min darkness value; the higher the value, the darker the color;
* float value between 0.0 and 1.0.
*/
fun Int.isColorDark(@FloatRange(from = 0.0, to = 1.0) threshold: Float = 0.9f): Boolean {
val darkness = 1 - (Color.red(this) * 0.299 + Color.green(this) * 0.587 + Color.blue(this) * 0.114) / 255
return darkness >= threshold
}
Upvotes: 0
Reputation: 1815
If you want to include alpha
channel in calculations:
fun isColorDark(color: Int): Boolean {
val darkness = (1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255) * (Color.alpha(color) / 255)
return darkness >= 0.5
}
Upvotes: 0
Reputation: 227
Simplifying the accepted answer a little
public boolean isColorDark(int color){
final double darkness = 1-(0.299*Color.red(color) + 0.587*Color.green(color) + 0.114*Color.blue(color))/255;
return !(darkness<0.5);
}
Upvotes: 0
Reputation: 2333
Another solution:
private static final int BRIGHTNESS_THRESHOLD = 130;
/**
* Calculate whether a color is light or dark, based on a commonly known
* brightness formula.
*
* @see {@literal http://en.wikipedia.org/wiki/HSV_color_space%23Lightness}
*/
public static boolean isColorDark(int color) {
return ((30 * Color.red(color) +
59 * Color.green(color) +
11 * Color.blue(color)) / 100) <= BRIGHTNESS_THRESHOLD;
}
Upvotes: 1
Reputation: 12122
In case one would like to find out whether background color is light or dark to determine what color to use for text drawn on top of it (white or black) – calculating luminance won't provide you correct value in all the cases.
Consider you have background color: #7f6fad
.
If you check its luminance (via ColorUtils#calculateLuminance
) you'll get: 0.1889803503770053
, which is below 0.5
and therefore should be considered as dark following that logic.
But if you follow WCAG you'll see that for general text contrast should be at least 4.5:1.
ColorUtils has method calculateContrast
which will give the following results:
4.393666669010922
4.779607007540106
One can see that contrast which white text gives is not enough, while black is good. Therefore if you'd like to check what color to draw on top of some generic background color it is better to check contrasts instead:
@ColorInt
fun getContrastColor(@ColorInt color: Int): Int {
val whiteContrast = ColorUtils.calculateContrast(Color.WHITE, color)
val blackContrast = ColorUtils.calculateContrast(Color.BLACK, color)
return if (whiteContrast > blackContrast) Color.WHITE else Color.BLACK
}
Upvotes: 14
Reputation: 4852
If you use support library v4 (or AndroidX), you can use ColorUtils.calculateLuminance(color)
, which returns luminance of color as float between 0.0
and 1.0
.
So you can do something like:
boolean isDark(int color) {
return ColorUtils.calculateLuminance(color) < 0.5;
}
See:
Note since Android API 24 there is also method: Color.luminance(color)
.
Upvotes: 103
Reputation: 163
public float getLightness(int color) {
int red = Color.red(color);
int green = Color.green(color);
int blue = Color.blue(color);
float hsl[] = new float[3];
ColorUtils.RGBToHSL(red, green, blue, hsl);
return hsl[2];
}
One could easily use the ColorUtils to check the lightness of a color.
if (getLightness(color) < 0.5f ){
// This color is too dark!
}
Upvotes: 7
Reputation: 2870
Android doesn't provide it, you can implement a method to determine this. Here a method to do that:
public boolean isColorDark(int color){
double darkness = 1-(0.299*Color.red(color) + 0.587*Color.green(color) + 0.114*Color.blue(color))/255;
if(darkness<0.5){
return false; // It's a light color
}else{
return true; // It's a dark color
}
}
Upvotes: 135