如何从UIColor获取反色?

27

例如,黑色的反色应该是白色。

10个回答

37

---- 编辑 ----

根据 @amleszk 的回答,我更新了 UIColor 的扩展/类别,并添加了这个方法:

Swift

func inverseColor() -> UIColor {
    var alpha: CGFloat = 1.0
    
    var red: CGFloat = 0.0, green: CGFloat = 0.0, blue: CGFloat = 0.0
    if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
        return UIColor(red: 1.0 - red, green: 1.0 - green, blue: 1.0 - blue, alpha: alpha)
    }
    
    var hue: CGFloat = 0.0, saturation: CGFloat = 0.0, brightness: CGFloat = 0.0
    if self.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) {
        return UIColor(hue: 1.0 - hue, saturation: 1.0 - saturation, brightness: 1.0 - brightness, alpha: alpha)
    }
    
    var white: CGFloat = 0.0
    if self.getWhite(&white, alpha: &alpha) {
        return UIColor(white: 1.0 - white, alpha: alpha)
    }
    
    return self
}

Objective-C

- (UIColor *)inverseColor {
    CGFloat alpha;
    
    CGFloat red, green, blue;
    if ([self getRed:&red green:&green blue:&blue alpha:&alpha]) {
        return [UIColor colorWithRed:1.0 - red green:1.0 - green blue:1.0 - blue alpha:alpha];
    }
    
    CGFloat hue, saturation, brightness;
    if ([self getHue:&hue saturation:&saturation brightness:&brightness alpha:&alpha]) {
        return [UIColor colorWithHue:1.0 - hue saturation:1.0 - saturation brightness:1.0 - brightness alpha:alpha];
    }
    
    CGFloat white;
    if ([self getWhite:&white alpha:&alpha]) {
        return [UIColor colorWithWhite:1.0 - white alpha:alpha];
    }
    
    return nil;
}

---- 已弃用 ----

根据@grc的答案,我创建了一个UIColor类别,并使用以下方法:

- (UIColor *)inverseColor {
    
    CGColorRef oldCGColor = self.CGColor;
    
    int numberOfComponents = CGColorGetNumberOfComponents(oldCGColor);
    
    // can not invert - the only component is the alpha
    // e.g. self == [UIColor groupTableViewBackgroundColor]
    if (numberOfComponents == 1) {
        return [UIColor colorWithCGColor:oldCGColor];
    }
    
    const CGFloat *oldComponentColors = CGColorGetComponents(oldCGColor);
    CGFloat newComponentColors[numberOfComponents];
    
    int i = numberOfComponents - 1;
    newComponentColors[i] = oldComponentColors[i]; // alpha
    while (--i >= 0) {
        newComponentColors[i] = 1 - oldComponentColors[i];
    }
    
    CGColorRef newCGColor = CGColorCreate(CGColorGetColorSpace(oldCGColor), newComponentColors);
    UIColor *newColor = [UIColor colorWithCGColor:newCGColor];
    CGColorRelease(newCGColor);
    
    return newColor;
}

这个极其陈旧的答案非常糟糕,应该被删除。 - Fattie

29

iOS5+

-(UIColor*) inverseColor
{
    CGFloat r,g,b,a;
    [self getRed:&r green:&g blue:&b alpha:&a];
    return [UIColor colorWithRed:1.-r green:1.-g blue:1.-b alpha:a];
}

这与 "1.0"(double)或 "1f"(float)相同。它只是告诉编译器我们将使用浮点数而不是整数。 - carlossless

25

这应该可以工作:

// oldColor is the UIColor to invert
const CGFloat *componentColors = CGColorGetComponents(oldColor.CGColor);

UIColor *newColor = [[UIColor alloc] initWithRed:(1.0 - componentColors[0])
                                           green:(1.0 - componentColors[1])
                                            blue:(1.0 - componentColors[2])
                                           alpha:componentColors[3]];

来源:如何检查UIColor是暗色还是亮色?


谢谢,你的答案非常好。但是如果oldColor是[UIColor colorWithWhite:1 alpha:1],那么newColor将会是透明的。 - Míng
4
这仅适用于RGB颜色。下面iwill的回答更好。 - Christian Beer

14

一种流行的做法是扩展 UIColor 类:

extension UIColor {
    func inverse () -> UIColor {
        var r:CGFloat = 0.0; var g:CGFloat = 0.0; var b:CGFloat = 0.0; var a:CGFloat = 0.0;
        if self.getRed(&r, green: &g, blue: &b, alpha: &a) {
            return UIColor(red: 1.0-r, green: 1.0 - g, blue: 1.0 - b, alpha: a)
        }
        return .black // Return a default colour
    }
}

1
这个不处理非RGB颜色空间,因此应该优先考虑iwill的答案。 - steipete
在我的情况下,对于每种颜色,它返回0 1 1 1。 - Makalele

8

Swift解决方案扩展UIColor,添加一个计算属性inverted

extension UIColor {
    var inverted: UIColor {
        var a: CGFloat = 0.0, r: CGFloat = 0.0, g: CGFloat = 0.0, b: CGFloat = 0.0
        return getRed(&r, green: &g, blue: &b, alpha: &a) ? UIColor(red: 1.0-r, green: 1.0-g, blue: 1.0-b, alpha: a) : .black
    }
}

可用于任何 UIColor 实例(.red.blue.white 等),例如:

view.backgroundColor = UIColor.blue.inverted //Results in yellow background
view.backgroundColor = UIColor.black.inverted //Results in white background

7

GRC的解决方案存在一个问题:CGColorGetComponents返回的是0.0-1.0的比例,而不是2-255。因此,你应该使用

UIColor *newColor = [[UIColor alloc] initWithRed:(1.0 - componentColors[0])
                                           green:(1.0 - componentColors[1])
                                            blue:(1.0 - componentColors[2])
                                           alpha:componentColors[3]];

否则一切都会是白色(1.0及更高版本)

和amleszk使用的方式类似,这里也是用1.-color代替255。顺便说一下,那个1.代表的是浮点数1.0,应该写成1.0而不是1.,以避免混淆。


2

对于所有来到这里寻找答案的Swifters,为了帮助您,以下是使用Swift应该看起来的样子:

func inverseColor(color: UIColor) -> UIColor{
    var a: CGFloat = 0.0; var r: CGFloat = 0.0; var g: CGFloat = 0.0; var b: CGFloat = 0.0;
    color.getRed(&r, green: &g, blue: &b, alpha: &a);
    return UIColor(red: -r, green: -g, blue: -b, alpha: a);
}

2

SwiftUI反转UIColor

当您使用SwiftUI时,可以使用View的colorInvert

.colorInvert()

2

我使用了Dade的答案并稍微调整了一下,因为我正在寻找一种漂亮的方式来计算给定背景颜色的文本前景色。

因此,如果您想要获得给定背景颜色的漂亮文本颜色,我建议您这样做。它会给出您所给定背景颜色中最亮的颜色:

extension UIColor {
    func maxBright() -> UIColor {
        var r:CGFloat = 0.0; var g:CGFloat = 0.0; var b:CGFloat = 0.0; var a:CGFloat = 0.0;
        if self.getRed(&r, green: &g, blue: &b, alpha: &a) {
            let d:CGFloat = 1.0 - max(r,g,b)
            return UIColor(red: r + d, green: g + d , blue: b + d, alpha: 1.0)

        }
        return self
    }
}

它的工作方式就像将RGB滑块向上滑动,直到最亮的组件达到最大值。

例如:

titleLable.backgroundColor = UIColor.blackColor()
titleLabel.textColor = titleLabel.backgroundColor?.maxBright()

将会给你一个黑底白字的标签。尝试其他颜色,你会看到有趣的结果 :)

这可能不是你想要的,但它确实为文本前/后景色提供了有趣的结果。

只是分享一下


0

你没有得到灰色的反色。所以当你使用灰色背景和其反色作为文本颜色时,就会出现这种情况。

这个方法甚至适用于灰色,我只是在@iWills的代码中添加了一些额外的代码。

//====== TO GET THE OPPOSIT COLORS =====
-(UIColor *)reverseColorOf :(UIColor *)oldColor
{
    CGColorRef oldCGColor = oldColor.CGColor;

    int numberOfComponents = CGColorGetNumberOfComponents(oldCGColor);
    // can not invert - the only component is the alpha
    if (numberOfComponents == 1) {
        return [UIColor colorWithCGColor:oldCGColor];
    }

    const CGFloat *oldComponentColors = CGColorGetComponents(oldCGColor);
    CGFloat newComponentColors[numberOfComponents];

    int i = numberOfComponents - 1;
    newComponentColors[i] = oldComponentColors[i]; // alpha
    while (--i >= 0) {
        newComponentColors[i] = 1 - oldComponentColors[i];
    }

    CGColorRef newCGColor = CGColorCreate(CGColorGetColorSpace(oldCGColor), newComponentColors);
    UIColor *newColor = [UIColor colorWithCGColor:newCGColor];
    CGColorRelease(newCGColor);

    //=====For the GRAY colors 'Middle level colors'
    CGFloat white = 0;
    [oldColor getWhite:&white alpha:nil];

    if(white>0.3 && white < 0.67)
    {
        if(white >= 0.5)
            newColor = [UIColor darkGrayColor];
        else if (white < 0.5)
            newColor = [UIColor blackColor];

    }
    return newColor;
}

灰色的反色是灰色。我知道这对大多数实际用途来说并不是非常有帮助,但这是数学上的现实。因此,“这适用于灰色”是相对的;它只有在您试图从源颜色获取高对比度的颜色时才会“起作用”。然而,我确实喜欢这个答案如何处理不同或未知的颜色空间。 - Falkreon
这个非常老的答案没有意义,很荒谬。 - Fattie
这个非常老的答案没有意义,它很荒谬。 - Fattie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接