检查 UIColor 是暗还是亮?

Posted

技术标签:

【中文标题】检查 UIColor 是暗还是亮?【英文标题】:Check if UIColor is dark or bright? 【发布时间】:2011-01-31 08:29:27 【问题描述】:

我需要确定选定的 UIColor(由用户选择)是暗色还是亮色,因此我可以更改位于该颜色之上的一行文本的颜色,以提高可读性。

以下是 Flash/Actionscript 中的示例(带演示): http://web.archive.org/web/20100102024448/http://theflashblog.com/?p=173

有什么想法吗?

干杯, 安德烈

更新

感谢大家的建议,下面是工作代码:

- (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");
    

再次感谢:)

【问题讨论】:

好像有些颜色没有3个组件,比如UIColor.black。 【参考方案1】:
- (BOOL)isColorLight:(UIColor*)color

    CGFloat white = 0;
    [color getWhite:&white alpha:nil];
    return (white >= .85);

添加Swift 5版本:

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

【讨论】:

这仅在UIColor 是灰度颜色时有效。随机 RGB 颜色不适用于此代码。【参考方案2】:

UIColor 有以下方法可以转换成HSB色彩空间

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

【讨论】:

【参考方案3】:

这是一个用于执行此检查的 Swift (3) 扩展。

此扩展程序适用于灰度颜色。但是,如果您使用 RGB 初始化程序创建所有颜色,而不是使用内置颜色,例如 UIColor.blackUIColor.white,那么您可以删除额外的检查。

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)
    

测试:

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

注意:更新到 Swift 3 12/7/18

【讨论】:

效果很好。使用 Swift 2.0 - 亮度计算时出现编译器错误:“表达式太复杂,无法在合理时间内解决;考虑将表达式分解为不同的子表达式”。我通过添加类型来修复它:“让亮度 = (((components[0] * 299.0) as CGFloat) + ((components[1] * 587.0) as CGFloat) + ((components[2] * 114.0)) as CGFloat ) / (1000.0 作为 CGFloat)" 我在使用 Swift 2.1 时遇到了同样的问题。我通过简单地为组件创建变量而不是使用components[0] 访问它们来解决这个问题。像这样:let componentColorX: CGFloat = components[1] Xcode 告诉我亮度 =“表达式太复杂,无法在合理的时间内解决;考虑将表达式分解为不同的子表达式” daidai,简化表达。最后的划分是不必要的。我们不需要在 0 - 1 范围内工作。不要除以 1000,然后只需检查值是否大于 500。【参考方案4】:

对我来说,只使用 CGColorGetComponents 没有用,我得到了 2 个 UIColors 组件,比如白色。所以我必须先检查颜色空间模型。 这就是我想出的最终成为@mattsven 答案的快速版本。

取自这里的色彩空间:https://***.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
    

【讨论】:

【参考方案5】:

Swift 4 版本

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)
    

【讨论】:

这可能不适用于 UIColor.white 等默认系统颜色,因为它只有 2 个组件,不是 RGB 表示。【参考方案6】:

更简单的 Swift 3 扩展:

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
    

【讨论】:

这可能不适用于 UIColor.white 等默认系统颜色,因为它只有 2 个组件,不是 RGB 表示。 真的!您可以将颜色转换为十六进制字符串,然后返回 UIColor 来解决这个问题。【参考方案7】:

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

【讨论】:

对我来说这个是最好的。您甚至可以在支票中设置白色范围以满足您的需求,并且超级简单和原生。谢谢。 ((rgb.red * 299) + (rgb.green * 587) + (rgb.blue * 114)) / 1000 更准确,例如颜色#7473E8,getWhite(&white, alpha: nil)是0.49656128883361816,但是这个公式是0.5044464148879051,所以公式的方式比getWhite好。【参考方案8】:

下面的方法是在 Swift 语言中根据白色来查找颜色是浅色还是深色。

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

以下方法是使用颜色组件在 Swift 中查找颜色是浅色还是深色。

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

【讨论】:

【参考方案9】:

使用 Erik Nedwidek 的回答,我想出了一小段代码,以便于包含。

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

【讨论】:

我使用了这段代码,效果很好,但不知道我什么时候设置了[UIColor blackColor],它返回darknessScore = 149.685。你能解释一下为什么会这样吗? 此代码不适用于非 RGB 颜色,例如 UIColor whiteColor, grayColor, blackColor @rmaddy 为什么会这样?或者为什么不是 whiteColor、grayColor 和 blackColor RGB 颜色? @rmaddy 如何以编程方式区分 RGB 颜色空间中的颜色与灰度之间的颜色? @maddy 没关系!感谢您的帮助 - ***.com/questions/1099569/…【参考方案10】:

我在一个类别中对这个问题的解决方案(取自此处的其他答案)。也适用于灰度颜色,在撰写本文时,其他答案都没有。

@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

【讨论】:

很好地处理非 RGB 颜色 - 就像一个魅力。【参考方案11】:

如果您更喜欢块版本:

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

【讨论】:

【参考方案12】:

W3C 有以下内容: http://www.w3.org/WAI/ER/WD-AERT/#color-contrast

如果您只处理黑色或白色文本,请使用上面的颜色亮度计算。如果低于 125,请使用白色文本。如果是 125 或以上,请使用黑色文本。

编辑 1:偏向黑色文本。 :)

编辑 2:要使用的公式是 ((Red value * 299) + (Green value * 587) + (Blue value * 114)) / 1000。

【讨论】:

你知道如何获取一种颜色的 red 、 green 和 blue 值吗? 您可以使用NSArray *components = (NSArray *)CGColorGetComponents([UIColor CGColor]); 获取颜色分量数组,包括alpha。文档没有指定它们的顺序,但我认为它是红色、绿色、蓝色、alpha。此外,从文档中,“数组的大小比颜色的颜色空间分量的数量大一。” - 它没有说明为什么...... 这很奇怪......使用: NSArray *components = (NSArray *) CGColorGetComponents(newColor.CGColor); NSLog(@"我的颜色分量 %f %f %f %f", components[0], components[1], components[2], components[3]);只是为了看看我是否能得到这些值,似乎只有 0 索引发生了变化,其他的将保持不变,不管我选择什么颜色。知道为什么吗? 知道了。你不能使用 NSArray。改用这个: const CGFloat *components = CGColorGetComponents(newColor.CGColor);另外,顺序是:红色是组件[0];绿色是组件[1];蓝色是组件[2]; alpha 是组件[3]; 啊,我的错。我以为它返回了一个 CFArrayRef,而不是一个 C 数组。对不起!【参考方案13】:

如果你想找到颜色的亮度,这里有一些伪代码:

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

如果大于 0.5,则为亮,否则为暗。

【讨论】:

您无法对每种颜色进行同等加权。我们的眼睛偏爱蓝色,在较小程度上偏爱红色。 @ErikNedwidek:很公平,这个问题只是询问颜色的亮度:)【参考方案14】:

对于所有不是灰色的东西,颜色的 RGB 反转通常与之形成强烈对比。 该演示只是反转颜色并对其进行去饱和(将其转换为灰色)。

但是生成一个漂亮舒缓的颜色组合是相当复杂的。 看看:

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

【讨论】:

如果有 iPhone 版本就好了:D 因此,如果我获得了一种颜色的 RGB 值(我不知道该怎么做)并创建了一种与这些值相反的新颜色,那应该可以在非常基本的层面上工作吗?

以上是关于检查 UIColor 是暗还是亮?的主要内容,如果未能解决你的问题,请参考以下文章

UIColor可以用深色和浅色两种颜色初始化吗?

从 UIColor 获得稍微更亮和更暗的颜色

将 NSColor 从 NSAttributedString 转换为 UIColor

如何将 UIColor 转换为 HEX 并在 NSLog 中显示

UIColor

CIColor 到 UIColor -> CIColor 没有为 UIColor UIExtendedSRGBColorSpace 定义