检查 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.black
和 UIColor.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 是暗还是亮?的主要内容,如果未能解决你的问题,请参考以下文章
将 NSColor 从 NSAttributedString 转换为 UIColor
如何将 UIColor 转换为 HEX 并在 NSLog 中显示
CIColor 到 UIColor -> CIColor 没有为 UIColor UIExtendedSRGBColorSpace 定义