Check if UIColor is dark or bright?

IosIphoneXcodeColorsUicolor

Ios Problem Overview


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://web.archive.org/web/20100102024448/http://theflashblog.com/?p=173

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

Ios Solutions


Solution 1 - Ios

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.

Solution 2 - Ios

Here is a Swift (3) extension to perform this check.

This extension works with greyscale colors. However, if you are creating all your colors with the RGB initializer and not using the built in colors such as UIColor.black and UIColor.white, then possibly you can remove the additional checks.

extension UIColor {
    
    // Check if the color is light or dark, as defined by the injected lightness threshold.
    // Some people report that 0.7 is best. I suggest to find out for yourself.
    // A nil value is returned if the lightness couldn't be determined.
    func isLight(threshold: Float = 0.5) -> Bool? {
        let originalCGColor = self.cgColor
        
        // Now we need to convert it to the RGB colorspace. UIColor.white / UIColor.black are greyscale and not RGB.
        // If you don't do this then you will crash when accessing components index 2 below when evaluating greyscale colors.
        let RGBCGColor = originalCGColor.converted(to: CGColorSpaceCreateDeviceRGB(), intent: .defaultIntent, options: nil)
        guard let components = RGBCGColor?.components else {
            return nil
        }
        guard components.count >= 3 else {
            return nil
        }
        
        let brightness = Float(((components[0] * 299) + (components[1] * 587) + (components[2] * 114)) / 1000)
        return (brightness > threshold)
    }
}

Tests:

func testItWorks() {
    XCTAssertTrue(UIColor.yellow.isLight()!, "Yellow is LIGHT")
    XCTAssertFalse(UIColor.black.isLight()!, "Black is DARK")
    XCTAssertTrue(UIColor.white.isLight()!, "White is LIGHT")
    XCTAssertFalse(UIColor.red.isLight()!, "Red is DARK")
}

Note: Updated to Swift 3 12/7/18

Solution 3 - Ios

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
}

Solution 4 - Ios

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

Solution 5 - Ios

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

Solution 6 - Ios

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

Solution 7 - Ios

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

Solution 8 - Ios

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
    }

Solution 9 - Ios

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

Solution 10 - Ios

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
}

Solution 11 - Ios

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/

Solution 12 - Ios

UIColor has the following method to convert to HSB color space:

- (BOOL)getHue:(CGFloat *)hue saturation:(CGFloat *)saturation brightness:(CGFloat *)brightness alpha:(CGFloat *)alpha;

Solution 13 - Ios

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

Added Swift 5 version:

var white: CGFloat = 0.0
color.getWhite(&white, alpha: nil)
return white >= .85 // Don't use white background

Solution 14 - Ios

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.

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
QuestionAndreView Question on Stackoverflow
Solution 1 - IosErik NedwidekView Answer on Stackoverflow
Solution 2 - Iosjosh-fuggleView Answer on Stackoverflow
Solution 3 - IosneoneyeView Answer on Stackoverflow
Solution 4 - IosRemy VanherweghemView Answer on Stackoverflow
Solution 5 - IosmattsvenView Answer on Stackoverflow
Solution 6 - IosKaiyuan XuView Answer on Stackoverflow
Solution 7 - IosSunkasView Answer on Stackoverflow
Solution 8 - IosLuchoView Answer on Stackoverflow
Solution 9 - IoskakilangitView Answer on Stackoverflow
Solution 10 - IosabhiView Answer on Stackoverflow
Solution 11 - Iosrep_movsdView Answer on Stackoverflow
Solution 12 - IosCuddyView Answer on Stackoverflow
Solution 13 - IosMike GlukhovView Answer on Stackoverflow
Solution 14 - IosBryan DennyView Answer on Stackoverflow