Question

I'm introducing "tagging" functionality in my application, and one of the ways I allow tags to be displayed is to set the text to the color the user has selected for each. My application has three themes with backgrounds that are white, black and a notepad-like brown (these could change/grow in the future). I want to be able to display the tag in its native color if it easily contrasts the background, and just use the default text color for each theme otherwise.

I've written a helper function to help me determine if the text will be masked, but its not 100% correct (I want it to determine if colors will be masked based on all three of the hsv components, and right now the saturation comparison isn't valid). The code is below.

    public static boolean colorWillBeMasked(int color, Application app){

      float[] hsv = new float[3];
      Color.colorToHSV(color, hsv);
      //note 0, black 1, white 2
      int theme = app.api.getThemeView();
      System.out.println("h=" +hsv[0]+ ", s=" +hsv[1]+ ", v=" +hsv[2]+", theme="+theme);

      if(android.R.color.transparent == color) return true;
      // color is dark
      if(hsv[2] <= .2){
          if(theme == 1) return true;
      }
      // color is light
      else if(hsv[2] >= .8) {
          if(theme == 2) return true;
      }
      return false;
   }

When calling this function with blue, red, transparent, black, yellow and green the output is as follows (respectively):

  • h=0.0, s=1.0, v=1.0, theme=1
  • h=229.41177, s=1.0, v=1.0, theme=1
  • h=267.6923, s=1.0, v=0.050980393, theme=1
  • h=0.0, s=0.0, v=0.0, theme=1
  • h=59.52941, s=1.0, v=1.0, theme=1
  • h=111.29411, s=1.0, v=1.0, theme=1

My question is: based on hue, saturation and value, how can you determine if text that is colored a certain way will show up on a white background vs a black background or if it will be masked? Please take my algorithm and improve it or help me create a new one.

Thanks in advance.

Was it helpful?

Solution

Solution that I came up with:

I ended up using an algorithm found on this blog to redefine my function as follows; I then adjusted the brightness cut-off on each end. Hope this helps someone.

public static boolean colorWillBeMasked(int color, Application app){
    if(android.R.color.transparent == color) return true;

    int[] rgb = {Color.red(color), Color.green(color), Color.blue(color)};

    int brightness =
        (int)Math.sqrt(
              rgb[0] * rgb[0] * .241 + 
              rgb[1] * rgb[1] * .691 + 
              rgb[2] * rgb[2] * .068);

    System.out.println("COLOR: " + color + ", BRIGHT: " + brightness);
    //note 0,black 1,classic 2
    int theme = app.api.getThemeView();

    // color is dark
    if(brightness <= 40){
        if(theme == 1) return true;
    }
    // color is light
    else if (brightness >= 215){
        if(theme == 2) return true;
    }
    return false;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top