2

I have been looking for a way to draw an image programatically for a while now. I found a fairly good solution:

UIGraphicsBeginImageContextWithOptions(CGSizeMake(36, 36), NO, 0.0);
UIImage *blank = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

But the downside of this is that in the same context I cannot create two or more images of different colours so I can use them as a background for a button for instance (for all three states). Yes, I know that I can set some resource PNG as the background of a UIButton, but if I would want that I wouldn't ask this question.

I would really like to learn how to create images programatically and use them, with different colours as background, in the same context, or maybe created in another context but ported to where I need them.

EDIT: To clarify furthermore, take this piece of code:

UIButton *button = [UIButton alloc] init];

button.frame = CGRectMake(0.0, 0.0, 200, 30);

//this is pefect
button.backgroundColor = [UIColor whiteColor];

//but, what if I want to have the UIControlStateNormal / UIControlStateHighlighted / UIControlStateDisabled with different background colors ?
[button setBackgroundColor: [UIColor blackColor] forState: ?] // dont't think so, right ?

In the case above I'm forced to use an image, if I want the button to look different when pressed or disabled, of course, the background, because the title and the title colour can be easily changed.

Roland
  • 9,321
  • 17
  • 79
  • 135
  • 1
    you know UIButton has a setBackgroundColor property? Why are you generated (from my understanding) solid colored images? Or are they not solid colors? – John Riselvato Dec 06 '13 at 16:43
  • Why can't you create multiple images from the same context? Get the context, fill it with the first color, get an image. Then fill the context with the second color, get a new image, and so on. – DrummerB Dec 06 '13 at 16:44
  • No, you cannot set different background colours, you can only: `[self setBackgroundImage:<#(UIImage *)image#> forState:<#(UIControlState)state#>];`. – Roland Dec 06 '13 at 17:00
  • You're correct, I was mistaken. You might like this answer: http://stackoverflow.com/a/9327750/525576 – John Riselvato Dec 06 '13 at 17:06
  • Thank you, that look exactly like something I was looking for. Same is @DrummerB's answer. – Roland Dec 06 '13 at 19:10

4 Answers4

3

You could just create a category on UIImage to return a new UIImage instance with a specific size and filled with a color:

+ (UIImage *)imageOfSize:(CGSize)size filledWithColor:(UIColor *)color {
    UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGRect rect = (CGRect){CGPointZero, size};
    CGContextFillRect(context, rect);
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}
DrummerB
  • 39,814
  • 12
  • 105
  • 142
  • This sounds like a good idea, just that I would use a subclass instead of category, I'm not that much into categories – Roland Dec 06 '13 at 16:54
  • uhh...? what would you subclass? UIImage? – John Riselvato Dec 06 '13 at 16:56
  • Research the key differences between a category and a subclass. This one is definitely a case for a category. – DrummerB Dec 06 '13 at 17:00
  • Yes, I would subclass `UIImage`, because it will, at some point, contain a lot of methods and I would prefer to keep myself away from categories. But if you have an argument against this reasoning, I would be happy to hear it. I have read a couple of articles and some of my work colleagues tend to avoid categories, but I did not see a good reason why everybody avoids it. – Roland Dec 06 '13 at 19:08
  • You might have forgotten the `context`: `CGContextRef context = UIGraphicsGetCurrentContext();` – Roland Dec 06 '13 at 19:27
  • And if I think about it, it makes sense to be in a category since it's not going to be project specific, at least this is the only reason I can think of as pro in being in a category – Roland Dec 06 '13 at 19:29
  • @rolandjitsu Subclassing doesn't make sense from a design point of view in my opinion. You're not creating a new kind of image, with different behavior or properties. You just add a shortcut to the existing class that could have very well been part of the original API. There are some classes where subclassing rarely (if ever) makes sense. Mostly these are the standard objects like `NSString`, `NSArray`, `NSDictionary`, `NSImage` (or `UIImage` on iOS). – DrummerB Dec 06 '13 at 19:34
  • Makes sense, and one last thing, what are your thoughts on some new custom colours that I use throughout the app, does it makes sense to subclass `UIColor` or should I add them as a category ? The only thing that I can think of is that is very specific to this project, and I think of categories as classes that I can just drop in other apps and reuse without any customisations. – Roland Dec 06 '13 at 19:51
  • 1
    Categories don't have to be reusable and subclasses can be reusable. This is not the main difference. I would use a category to declare custom colors: http://stackoverflow.com/questions/2718507/how-do-i-define-constant-values-of-uicolor – DrummerB Dec 06 '13 at 19:54
2

I have created a CocoaPod that provides [UIImage imageWithColor:]:

pod 'UIImage+ImageWithColor'

mxcl
  • 26,392
  • 12
  • 99
  • 98
1

check out this:

+ (UIImage *)imageWithColor:(UIColor *)color {
    CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;
}

optionally you can draw custom image from layer

+ (UIImage *)imageFromLayer:(CALayer *)layer{
    UIGraphicsBeginImageContext([layer frame].size);
    [layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return outputImage;
}
debris
  • 503
  • 6
  • 10
0

Try like this the same code:-

    UIImage *thumbnail =[UIImage imageNamed:@"yourImg.png"];
    CGSize itemSize = CGSizeMake(35, 35);
    UIGraphicsBeginImageContext(itemSize);
    CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
    [thumbnail drawInRect:imageRect];
    cell.imageView.image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
Hussain Shabbir
  • 14,801
  • 5
  • 40
  • 56