Check if UIColor is dark or bright?

I need to determine whether a selected UIColor (picked by the user) is dark or bright, so I can change the color of a line of text that sits on top of that color, for better readability.

Here’s an example in Flash/Actionscript (with demo):
http://theflashblog.com/?p=173

  • Rich text editor library for iOS
  • Determine if current local time is between two times (ignoring the date portion)
  • Storyboard weird controller view frame origins
  • Resize the Table cell height as per downloaded image height
  • Error delivering iOS App update. “This bundle is invalid. Apple is not currently accepting applications built with this version of the SDK.”
  • Subversion (SVN) and static libraries (.a files) compatibility?
  • Any thoughts?

    Cheers,
    Andre

    UPDATE

    Thanks to everyone’s suggestions, here’s the working code:

    - (void) updateColor:(UIColor *) newColor
    {
        const CGFloat *componentColors = CGColorGetComponents(newColor.CGColor);
    
        CGFloat colorBrightness = ((componentColors[0] * 299) + (componentColors[1] * 587) + (componentColors[2] * 114)) / 1000;
        if (colorBrightness < 0.5)
        {
            NSLog(@"my color is dark");
        }
        else
        {
            NSLog(@"my color is light");
        }
    }
    

    Thanks once again 🙂

    14 Solutions Collect From Internet About “Check if UIColor is dark or bright?”

    W3C has the following:
    http://www.w3.org/WAI/ER/WD-AERT/#color-contrast

    If you’re only doing black or white text, use the color brightness calculation above. If it is below 125, use white text. If it is 125 or above, use black text.

    edit 1: bias towards black text. 🙂

    edit 2: The formula to use is ((Red value * 299) + (Green value * 587) + (Blue value * 114)) / 1000.

    Using Erik Nedwidek’s answer, I came up with that little snippet of code for easy inclusion.

    - (UIColor *)readableForegroundColorForBackgroundColor:(UIColor*)backgroundColor {
        size_t count = CGColorGetNumberOfComponents(backgroundColor.CGColor);
        const CGFloat *componentColors = CGColorGetComponents(backgroundColor.CGColor);
    
        CGFloat darknessScore = 0;
        if (count == 2) {
            darknessScore = (((componentColors[0]*255) * 299) + ((componentColors[0]*255) * 587) + ((componentColors[0]*255) * 114)) / 1000;
        } else if (count == 4) {
            darknessScore = (((componentColors[0]*255) * 299) + ((componentColors[1]*255) * 587) + ((componentColors[2]*255) * 114)) / 1000;
        }
    
        if (darknessScore >= 125) {
            return [UIColor blackColor];
        }
    
        return [UIColor whiteColor];
    }
    

    And here is a Swift extension:

    extension UIColor
    {
        func isLight() -> Bool
        {
            let components = CGColorGetComponents(self.CGColor)
            let brightness = ((components[0] * 299) + (components[1] * 587) + (components[2] * 114)) / 1000
    
            if brightness < 0.5
            {
                return false
            }
            else
            {
                return true
            }
        }
    }
    

    Swift3

    extension UIColor {
        var isLight: Bool {
            var white: CGFloat = 0
            getWhite(&white, alpha: nil)
            return white > 0.5
        }
    }
    
    // Usage
    if color.isLight {
        label.textColor = UIColor.black
    } else {
        label.textColor = UIColor.white
    }
    

    My solution to this problem in a category (drawn from other answers here). Also works with grayscale colors, which at the time of writing none of the other answers do.

    @interface UIColor (Ext)
    
        - (BOOL) colorIsLight;
    
    @end
    
    @implementation UIColor (Ext)
    
        - (BOOL) colorIsLight {
            CGFloat colorBrightness = 0;
    
            CGColorSpaceRef colorSpace = CGColorGetColorSpace(self.CGColor);
            CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace);
    
            if(colorSpaceModel == kCGColorSpaceModelRGB){
                const CGFloat *componentColors = CGColorGetComponents(self.CGColor);
    
                colorBrightness = ((componentColors[0] * 299) + (componentColors[1] * 587) + (componentColors[2] * 114)) / 1000;
            } else {
                [self getWhite:&colorBrightness alpha:0];
            }
    
            return (colorBrightness >= .5f);
        }
    
    @end
    

    If you prefer the block version:

    BOOL (^isDark)(UIColor *) = ^(UIColor *color){
        const CGFloat *component = CGColorGetComponents(color.CGColor);
        CGFloat brightness = ((component[0] * 299) + (component[1] * 587) + (component[2] * 114)) / 1000;
    
        if (brightness < 0.75)
            return  YES;
        return NO;
    };
    

    Simpler Swift 3 extension:

    extension UIColor {
        func isLight() -> Bool {
            guard let components = cgColor.components else { return false }
            let redBrightness = components[0] * 299
            let greenBrightness = components[1] * 587
            let blueBrightness = components[2] * 114
            let brightness = (redBrightness + greenBrightness + blueBrightness) / 1000
            return brightness > 0.5
        }
    }
    

    For everything that’s not grayish, the RGB inverse of a color is usually highly contrasted with it.
    The demo just inverts the color and desaturates it (converts it to a gray).

    But generating a nice soothing combination of colors is quite complicated.
    Look at :

    http://particletree.com/notebook/calculating-color-contrast-for-legible-text/

    Following method is find color is light or dark in Swift language based on white in color.

    func isLightColor(color: UIColor) -> Bool 
    {
       var white: CGFloat = 0.0
       color.getWhite(&white, alpha: nil)
    
       var isLight = false
    
       if white >= 0.5
       {
           isLight = true
           NSLog("color is light: %f", white)
       }
       else
       {
          NSLog("Color is dark: %f", white)
       }
    
       return isLight
    }
    

    Following method is find color is light or dark in Swift using color components.

    func isLightColor(color: UIColor) -> Bool 
    {
         var isLight = false
    
         var componentColors = CGColorGetComponents(color.CGColor)
    
         var colorBrightness: CGFloat = ((componentColors[0] * 299) + (componentColors[1] * 587) + (componentColors[2] * 114)) / 1000;
         if (colorBrightness >= 0.5)
         {
            isLight = true
            NSLog("my color is light")
         }
         else
         {
            NSLog("my color is dark")
         }  
         return isLight
    }
    

    Swift 4 Version

    extension UIColor {
        func isLight() -> Bool {
            guard let components = cgColor.components, components.count > 2 else {return false}
            let brightness = ((components[0] * 299) + (components[1] * 587) + (components[2] * 114)) / 1000
            return (brightness > 0.5)
        }
    }
    

    If you want to find the brightness of the color, here is some pseudo code:

    public float GetBrightness(int red, int blue, int green)
    {
        float num = red / 255f;
        float num2 = blue / 255f;
        float num3 = green / 255f;
        float num4 = num;
        float num5 = num;
        if (num2 > num4)
            num4 = num2;
        if (num3 > num4)
            num4 = num3;
        if (num2 < num5)
            num5 = num2;
        if (num3 < num5)
            num5 = num3;
        return ((num4 + num5) / 2f);
    }
    

    If it is > 0.5 it is bright, and otherwise dark.

    - (BOOL)isColorLight:(UIColor*)color
    {
        CGFloat white = 0;
        [color getWhite:&white alpha:nil];
        return (white >= .5);
    }
    

    Using HandyUIKit makes this a no-brainer, for example:

    import HandyUIKit    
    
    UIColor.black.hlca.luminance     // => 0.0
    UIColor.white.hlca.luminance     // => 1.0
    UIColor.lightGray.hlca.luminance // => 0.70
    UIColor.darkGray.hlca.luminance  // => 0.36
    UIColor.red.hlca.luminance       // => 0.53
    UIColor.green.hlca.luminance     // => 0.87
    UIColor.blue.hlca.luminance      // => 0.32
    

    Simply using .hlca.luminance on any UIColor instance will give you the correct value for perceived lightness. Most other approaches don’t take into account the fact that humans perceive different colors (even when saturation and brightness are the same) at different brightness levels. The luminance values takes this into account.

    Read this great blog post or the Wikipedia entry on the LAB color space for further explanation. They’ll also explain why the HSB color system with its brightness value is only half of the solution.

    Just as a hint: Notice that the luminance value of the pure green color is much higher than on the pure blue color. That’s simply because humans perceive pure blue as a much darker color than pure green.

    For me using only CGColorGetComponents didn’t worked, I get 2 components for UIColors like white. So I have to check the color spaceModel first.
    This is what I came up with that ended up being the swift version of @mattsven’s answer.

    Color space taken from here: https://stackoverflow.com/a/16981916/4905076

    extension UIColor {
        func isLight() -> Bool {
            if let colorSpace = self.cgColor.colorSpace {
                if colorSpace.model == .rgb {
                    guard let components = cgColor.components, components.count > 2 else {return false}
    
                    let brightness = ((components[0] * 299) + (components[1] * 587) + (components[2] * 114)) / 1000
    
                    return (brightness > 0.5)
                }
                else {
                    var white : CGFloat = 0.0
    
                    self.getWhite(&white, alpha: nil)
    
                    return white >= 0.5
                }
            }
    
            return false
        }