8

I have colorA which is [UIColor blueColor], and colorB, which is [UIColor redColor]. Is this possible for me to render a [UIColor purple]? How can it be implemented? Thanks.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
DNB5brims
  • 29,344
  • 50
  • 131
  • 195
  • I assume that you tried calling `CGColorGetComponents`, averaging them up, and then making a color from the components, right? – Sergey Kalinichenko Oct 30 '12 at 04:49
  • CAGradientLayer *gradiant = [CAGradientLayer layer]; gradiant.frame = self.view.bounds; gradiant.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithRed:0.90 green:0.99 blue:1.0 alpha:1] CGColor],(id)[[UIColor colorWithRed:0.52 green:0.96 blue:0.98 alpha:1] CGColor], nil]; [self.view.layer insertSublayer:gradiant atIndex:0]; – venki Dec 23 '16 at 06:25

6 Answers6

30

Inelegant, but it works:

UIColor* blend( UIColor* c1, UIColor* c2, float alpha )
{
    alpha = MIN( 1.f, MAX( 0.f, alpha ) );
    float beta = 1.f - alpha;
    CGFloat r1, g1, b1, a1, r2, g2, b2, a2;
    [c1 getRed:&r1 green:&g1 blue:&b1 alpha:&a1];
    [c2 getRed:&r2 green:&g2 blue:&b2 alpha:&a2];
    CGFloat r = r1 * beta + r2 * alpha;
    CGFloat g = g1 * beta + g2 * alpha;
    CGFloat b = b1 * beta + b2 * alpha;
    return [UIColor colorWithRed:r green:g blue:b alpha:1.f];
}

More elegant:

UIColor+Extensions.h:

@interface UIColor (Extensions)

- (UIColor*)blendWithColor:(UIColor*)color2 alpha:(CGFloat)alpha2;

@end

UIColor+Extensions.m:

@implementation UIColor (Extensions)

- (UIColor*)blendWithColor:(UIColor*)color2 alpha:(CGFloat)alpha2
{
    alpha2 = MIN( 1.0, MAX( 0.0, alpha2 ) );
    CGFloat beta = 1.0 - alpha2;
    CGFloat r1, g1, b1, a1, r2, g2, b2, a2;
    [self getRed:&r1 green:&g1 blue:&b1 alpha:&a1];
    [color2 getRed:&r2 green:&g2 blue:&b2 alpha:&a2];
    CGFloat red     = r1 * beta + r2 * alpha2;
    CGFloat green   = g1 * beta + g2 * alpha2;
    CGFloat blue    = b1 * beta + b2 * alpha2;
    CGFloat alpha   = a1 * beta + a2 * alpha2;
    return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
}

@end

Swift 3/4:

extension UIColor
{
func mixin(infusion:UIColor, alpha:CGFloat) -> UIColor {
    let alpha2 = min(1.0, max(0, alpha))
    let beta = 1.0 - alpha2

    var r1:CGFloat = 0, r2:CGFloat = 0
    var g1:CGFloat = 0, g2:CGFloat = 0
    var b1:CGFloat = 0, b2:CGFloat = 0
    var a1:CGFloat = 0, a2:CGFloat = 0
    if getRed(&r1, green: &g1, blue: &b1, alpha: &a1) &&
        infusion.getRed(&r2, green: &g2, blue: &b2, alpha: &a2)
    {
        let red     = r1 * beta + r2 * alpha2;
        let green   = g1 * beta + g2 * alpha2;
        let blue    = b1 * beta + b2 * alpha2;
        let alpha   = a1 * beta + a2 * alpha2;
        return UIColor(red: red, green: green, blue: blue, alpha: alpha)
    }
    // epique de las failuree
    return self
}
}
Anton Tropashko
  • 5,486
  • 5
  • 41
  • 66
Mark
  • 681
  • 7
  • 15
  • 2
    UIColor* purple = [[UIColor blueColor] blendWithColor:[UIColor redColor] alpha:0.5]; – Mark Feb 16 '14 at 21:25
  • @Mark Great answer. Would like to ask: can you please give some explanation to the methods above such as the use of beta and alpha here and the calculations applied on them? I am just a curious beast that instead of just using something that works, I would like to know why. I already +1'ed days ago. Wish I could do that again. Thanks in advance. – Unheilig Feb 17 '14 at 10:51
  • @Unheilig Thanks! alpha2 is the alpha factor applied to the color2 -- that is, alpha2 = 0.0 makes color2 "transparent" and alpha2 = 1.0 makes color2 fully opaque (obscuring the self color). alpha2 is clamped between 0.0 and 1.0 to avoid any side-effects due to bad alpha2 values. Then, beta is just the "alpha" for color1. I chose "beta" instead of alpha1 to make the value stand out more clearly in the code. – Mark Feb 21 '14 at 16:44
  • 4
    **NOTE** this only works for colors in the RGB space. For example, this will not work on [UIColor whiteColor] as that is not in RGB. – Valentin Shamardin Feb 27 '14 at 10:04
  • 1
    @Mark So alpha2 is a2? Edit: if I get it right, it is more like the level of blending and not related to transparency – Robin Vekety Mar 16 '16 at 23:16
  • You should definetly take gamma into account by squaring each component and then square rooting the final values – Downgoat May 02 '17 at 05:00
4

Ask each input color for its RGBA components using -[UIColor getRed:green:blue:alpha:]. Average the components from each, and create a new color using +[UIColor colorWithRed:green:blue:alpha:].

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • Note: make sure you divide the red: green: blue: paremeters by 256.0 – MCKapur Oct 30 '12 at 04:52
  • @TeenDev That would be a mistake, since `getRed:green:blue:alpha:` returns values between 0 and 1, and `colorWithRed:green:blue:alpha:` takes values between 0 and 1. – rob mayoff Oct 30 '12 at 05:01
  • Oh ok, colorWithRed:green:blue if you pass numbers above 1 then you need to divide by 256.0 (since general RGB spectrums online are specified in > 1)..... that is a problem I always face when trying to insert RGB numbers in! – MCKapur Oct 30 '12 at 06:37
  • 1
    @MCKapur you mean 255.0 not 256.0 – Albert Renshaw Feb 12 '14 at 17:57
  • 2
    There are 256 color ints but it starts at 0 so the range is 0-255 (which is 256 int values in total). But 255 = max(RGB) and 1 = max(component) and 255/255 = 1. – Albert Renshaw Feb 12 '14 at 17:59
  • Color components are not 8 bit integers. How do you think a 30 bit (10 bit per component) display is going to work if you only have 8 bit integers? – gnasher729 Aug 07 '20 at 07:51
  • This answer is terrible anyway. I should have recommended averaging `hue`, `saturation` and `brightness`, not `red`, `green`, and `blue`. You get much better results if you operate in HSV space. – rob mayoff Aug 07 '20 at 13:39
3

Swift5 UIColor Extension

extension UIColor {
    func add(_ overlay: UIColor) -> UIColor {
        var bgR: CGFloat = 0
        var bgG: CGFloat = 0
        var bgB: CGFloat = 0
        var bgA: CGFloat = 0
        
        var fgR: CGFloat = 0
        var fgG: CGFloat = 0
        var fgB: CGFloat = 0
        var fgA: CGFloat = 0
        
        self.getRed(&bgR, green: &bgG, blue: &bgB, alpha: &bgA)
        overlay.getRed(&fgR, green: &fgG, blue: &fgB, alpha: &fgA)
        
        let r = fgA * fgR + (1 - fgA) * bgR
        let g = fgA * fgG + (1 - fgA) * bgG
        let b = fgA * fgB + (1 - fgA) * bgB
        
        return UIColor(red: r, green: g, blue: b, alpha: 1.0)
    }
    
    static func +(lhs: UIColor, rhs: UIColor) -> UIColor {
        return lhs.add(rhs)
    }
}

Usage

let opacity: CGFloat = 0.6
let start = UIColor.red
let end = UIColor.blue
let combined = start.withAlphaComponent(opacity) + end.withAlphaComponent(1-opacity)
Li Jin
  • 1,879
  • 2
  • 16
  • 23
1

Since it is 2020 now, and we have "Dark Mode" available, many "colours" are not just colours anymore, but automatically adapt to color changes. They are created by calling UIColor(dynamicProvider: ...).

You should check if both colors are dynamic colors, and if they are, return a dynamic color. Mixing one dynamic color and a non-dynamic color doesn't really make sense, so in that case return a non-dynamic color.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
0

You can't mix two UIColors directly as you mention in your question. Anyways there is an example to mix two colors using other schemes. The link for same is as follows:

Link Here

iCreative
  • 1,499
  • 1
  • 9
  • 22
  • 4
    To present a link is not an answer. Besides, the project where the link points to doesn't succeed very well with the mixing. – turingtested Dec 11 '16 at 14:58
-1

If you want to use purple color then its not a big deal.All the UIColor are rgb color.You can simply pass the RGB value for each color and can get the desired color.Use this link to convert hex value of any color to convert in UIColor. http://www.touch-code-magazine.com/web-color-to-uicolor-convertor/

like #color code for green is #008400: [UIColor colorWithRed:0 green:0.518 blue:0 alpha:1] /#008400/

Abhinav
  • 191
  • 8