【问题标题】:Check if UIColor is dark or bright?检查 UIColor 是暗还是亮?
【发布时间】: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。

标签: ios iphone xcode colors uicolor


【解决方案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://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
        }
    

    【讨论】:

      【解决方案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 没关系!感谢您的帮助 - stackoverflow.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 值(我不知道该怎么做)并创建了一种与这些值相反的新颜色,那应该可以在非常基本的层面上工作吗?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-04-22
          • 2010-12-17
          • 2011-08-16
          • 1970-01-01
          • 2021-11-14
          • 1970-01-01
          • 2014-07-18
          相关资源
          最近更新 更多