160

I'm creating a colored image like this:

CGRect rect = CGRectMake(0, 0, 1, 1);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context,
                                   [[UIColor redColor] CGColor]);
//  [[UIColor colorWithRed:222./255 green:227./255 blue: 229./255 alpha:1] CGColor]) ;
CGContextFillRect(context, rect);
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

and then use it as the background image of a button:

[resultButton setBackgroundImage:img forState:UIControlStateNormal];

This works great using the redColor, however I want to use an RGB color (as shown in the commented line). When I use the RGB color, the buttons background isn't changed.

What am I missing?

Juan Boero
  • 6,281
  • 1
  • 44
  • 62
Thorsten
  • 12,921
  • 17
  • 60
  • 79

7 Answers7

150

I created a category around UIButton to be able to set the background color of the button and set the state. You might find this useful.

@implementation  UIButton (ButtonMagic)

- (void)setBackgroundColor:(UIColor *)backgroundColor forState:(UIControlState)state {
    [self setBackgroundImage:[UIButton imageFromColor:backgroundColor] forState:state];
}

+ (UIImage *)imageFromColor:(UIColor *)color {
    CGRect rect = CGRectMake(0, 0, 1, 1);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

This will be part of a set of helper categories I'm open sourcing this month.

Swift 2.2

extension UIImage {
static func fromColor(color: UIColor) -> UIImage {
    let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
    UIGraphicsBeginImageContext(rect.size)
    let context = UIGraphicsGetCurrentContext()
    CGContextSetFillColorWithColor(context, color.CGColor)
    CGContextFillRect(context, rect)
    let img = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return img
  }
}

Swift 3.0

extension UIImage {
    static func from(color: UIColor) -> UIImage {
        let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
        UIGraphicsBeginImageContext(rect.size)
        let context = UIGraphicsGetCurrentContext()
        context!.setFillColor(color.cgColor)
        context!.fill(rect)
        let img = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return img!
    }
}

Use as

let img = UIImage.from(color: .black)
CodeBender
  • 35,668
  • 12
  • 125
  • 132
ScottWasserman
  • 1,700
  • 1
  • 11
  • 8
  • 2
    Rather than being a category on UIButton, though now in Swift we are on extensions rather than categories, don't you think it would be best to have an extension on UIImage for the initializer rather than UIButton – SwiftMatt Jan 15 '16 at 10:51
  • Can I use this to create an image of certain dimensions? How do I do it? Sorry if my question, appears very naive.. :-/ – Shyam Jun 09 '17 at 10:43
  • If you're just talking about creating a rectangle with specific dimensions then change the width and height to whatever you'd like it to be. – ScottWasserman Jun 19 '17 at 19:33
14

Xamarin.iOS solution

 public UIImage CreateImageFromColor()
 {
     var imageSize = new CGSize(30, 30);
     var imageSizeRectF = new CGRect(0, 0, 30, 30);
     UIGraphics.BeginImageContextWithOptions(imageSize, false, 0);
     var context = UIGraphics.GetCurrentContext();
     var red = new CGColor(255, 0, 0);
     context.SetFillColor(red);
     context.FillRect(imageSizeRectF);
     var image = UIGraphics.GetImageFromCurrentImageContext();
     UIGraphics.EndImageContext();
     return image;
 }
Ahmad
  • 603
  • 1
  • 8
  • 17
ben
  • 3,126
  • 3
  • 37
  • 51
6

Are you using ARC? The problem here is that you don't have a reference to the UIColor object that you're trying to apply; the CGColor is backed by that UIColor, but ARC will deallocate the UIColor before you have a chance to use the CGColor.

The clearest solution is to have a local variable pointing to your UIColor with the objc_precise_lifetime attribute.

You can read more about this exact case on this article about UIColor and short ARC lifetimes or get more details about the objc_precise_lifetime attribute.

Jesse Rusak
  • 56,530
  • 12
  • 101
  • 102
  • A valid observation, but that would result in a crash, which it sounds like the OP hasn't observed. – Justin Spahr-Summers Jun 30 '12 at 00:51
  • Not necessarily; it depends on the details of how CGColor and CGContextFillRect interact, not to mention other details that might change from OS version to OS version. Certainly it could be something else, but since the code is broken as written (if ARC is being used) it's a first step at least. – Jesse Rusak Jun 30 '12 at 01:12
  • My code was from the pre-ARC days. – Thorsten Aug 15 '12 at 20:15
5

Add the dots to all values:

[[UIColor colorWithRed:222./255. green:227./255. blue: 229./255. alpha:1] CGColor]) ;

Otherwise, you are dividing float by int.

iGerm
  • 83
  • 1
  • 1
  • 5
    Not true - the integer argument is automatically promoted to a floating point value (double in this case) before the expression is evaluated, because the left hand operand is of type double. [See this answer for a detailed explanation](http://stackoverflow.com/questions/5563000/implicit-type-conversion-rules-in-c-operators) – Jan Holecek Sep 30 '13 at 12:54
4
CGContextSetFillColorWithColor(context,[[UIColor colorWithRed:(255/255.f) green:(0/255.f) blue: (0/255.f) alpha:1] CGColor]);
Prasad G
  • 6,702
  • 7
  • 42
  • 65
Muzamil Hassan
  • 841
  • 1
  • 11
  • 23
  • Not sure what you mean with your answer .. I was not trying to replace colorRed with RGB values, but use my own values instead - which doesn't seem to work. – Thorsten Aug 15 '12 at 20:14
4

I suppose that 255 in 227./255 is perceived as an integer and divide is always return 0

aknew
  • 1,101
  • 7
  • 23
  • Thanks for the idea (also suggested by someone who deleted his answer). The division works fine as it is, even when building the color from properly set floats (dummy vars declared and their value checked in the debugger), setting the background image does not do anything. – Thorsten Jun 27 '11 at 19:59
4

Your code works fine. You can verify the RGB colors with Iconfactory's xScope. Just compare it to [UIColor whiteColor].

bdunagan
  • 1,202
  • 12
  • 15