Check if color is dark or light in Android

AndroidColorsBackground

Android Problem Overview


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?

Android Solutions


Solution 1 - Android

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
    }
}

Solution 2 - Android

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).

Solution 3 - Android

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!
}

Solution 4 - Android

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:

  • For white text color: 4.393666669010922
  • For black text color: 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
}

Solution 5 - Android

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;
    }

Solution 6 - Android

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);
}

Solution 7 - Android

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
}

Solution 8 - Android

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
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioniGio90View Question on Stackoverflow
Solution 1 - AndroidadbocoView Answer on Stackoverflow
Solution 2 - AndroidRobyerView Answer on Stackoverflow
Solution 3 - AndroidBrandon BahretView Answer on Stackoverflow
Solution 4 - AndroidkrossovochkinView Answer on Stackoverflow
Solution 5 - AndroidCícero MouraView Answer on Stackoverflow
Solution 6 - AndroidTheN3wbieView Answer on Stackoverflow
Solution 7 - AndroidAmirView Answer on Stackoverflow
Solution 8 - AndroidBigStView Answer on Stackoverflow