UIImage from UIColor with alpha - ios

I am trying to create a UIImage from this UIColor value I have. The UIImage is being created, but the alpha value is lost. The image remains opaque. I am using the following code:
#implementation GetImage
+ (UIImage *)imageWithColor:(UIColor *)color andSize:(CGSize)size
{
UIImage *img = nil;
CGRect rect = CGRectMake(0, 0, size.width, size.height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context,
color.CGColor);
CGContextFillRect(context, rect);
img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
#end
Which I call like so:
-(void) setButtonColours{
UIImage *img1, *img2;
UIColor *red = [UIColor colorWithRed:205.0/255.0 green:68.0/255.0 blue:51.0/255.0 alpha:1.0],
*blue = [UIColor colorWithRed:71.0/255.0 green:97.0/255.0 blue:151.0/255.0 alpha:1.0];
img1 = [GetImage imageWithColor: blue andSize: self.dummyButton.frame.size];
img2 = [GetImage imageWithColor: red andSize: self.dummyButton.frame.size];
[self.dummyButton setBackgroundImage: img1 forState:UIControlStateNormal];
[self.dummyButton setBackgroundImage: img2 forState:UIControlStateSelected];
}
Any idea what I'm missing?

You are creating an opaque image context.
Replace this line:
UIGraphicsBeginImageContext(rect.size);
with:
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);

In the event someone finds this question and they are looking for the Monotouch implementation:
public class ColorRGBA
{
public float Red=0;
public float Green=0;
public float Blue=0;
public float Alpha=0;
public ColorRGBA (float red, float green, float blue, float alpha)
{
Red = red;
Green = green;
Blue = blue;
Alpha = alpha;
}
}
//then from within a custom mt.d element
private ColorRGBA color;
public override UITableViewCell GetCell (UITableView tv)
{
//create square with color
var imageSize = new SizeF(30, 30);
var imageSizeRectF = new RectangleF (0, 0, 30, 30);
UIGraphics.BeginImageContextWithOptions (imageSize, false, 0);
var context = UIGraphics.GetCurrentContext ();
context.SetFillColor (color.Red, color.Green, color.Blue, color.Alpha);
context.FillRect (imageSizeRectF);
var image = UIGraphics.GetImageFromCurrentImageContext ();
UIGraphics.EndImageContext ();
var cell = base.GetCell(tv);
cell.Accessory = UITableViewCellAccessory.DisclosureIndicator;
cell.ImageView.Image = image;
return cell;
}

For those interested, here is a simple rewrite in Swift 4+:
import UIKit
extension UIImage {
class func colorAsImage(from color:UIColor, for size:CGSize) -> UIImage? {
var img:UIImage?
let rect = CGRect(x:0.0, y:0.0, width: size.width, height: size.height)
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0)
guard let context = UIGraphicsGetCurrentContext() else { return nil }
context.setFillColor(color.cgColor)
context.fill(rect)
img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
guard let colorImage = img else { return nil }
return colorImage
}
}

Related

How to prevent bold images with UIImageRenderingModeAlwaysTemplate

My application has a toolbar with image buttons on them (subclass of UIButton); when the user switches on the "Bold text" accessibility option, not only the text becomes bold but the images follow suit.
This is the toolbar in normal mode:
When the "bold text" is enabled:
It seems to be caused by my UIButton subclass, which is included below. I'm using this class to apply an image tint colour when the button is clicked, disabled, etc. and prevents having to include multiple states of each button. For that I'm using the UIImageRenderingModeAlwaysTemplate which reportedly exhibits this observed behaviour.
I've tried to uncheck the "Accessibility" option in the interface builder, but that had no effect at all. Is there a way to fix this?
#import "AppButton.h"
#implementation AppButton
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
[self initialize];
}
return self;
}
- (void)initialize
{
self.adjustsImageWhenHighlighted = NO;
[self setImage:[[self imageForState:UIControlStateNormal] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
}
- (void)updateButtonView
{
if (!self.enabled) {
self.imageView.tintColor = [UIColor colorWithRGBValue:RGBValueC9];
} else if (self.highlighted) {
self.imageView.tintColor = self.highlightTintColor;
} else {
self.imageView.tintColor = self.tintColor;
}
}
- (void)setHighlighted:(BOOL)highlighted
{
[super setHighlighted:highlighted];
[self updateButtonView];
}
- (void)setEnabled:(BOOL)enabled
{
[super setEnabled:enabled];
[self updateButtonView];
}
- (void)setTintColor:(UIColor *)tintColor
{
[super setTintColor:tintColor];
[self updateButtonView];
}
#end
I recommend you to use a custom category to tint your image buttons. Here is a simple implementation that does just that:
UIImage+TintImage.h
#interface UIImage (TintImage)
- (UIImage *)imageTintedWithColor:(UIColor *)tintColor;
#end
UIImage+TintImage.m
#import "UIImage+TintImage.h"
#implementation UIImage (TintImage)
- (UIImage *)imageTintedWithColor:(UIColor *)tintColor
{
if (tintColor == nil) {
tintColor = [UIColor whiteColor];
}
CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
// Tint image
[tintColor set];
UIRectFill(rect);
[self drawInRect:rect blendMode:kCGBlendModeDestinationIn alpha:1.0f];
UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return tintedImage;
}
#end
To use it, just import "UIImage+TintImage.h", then do the following:
UIImage *originalImage = [UIImage imageNamed:#"icn-menu"];
UIImage *tintedImage = [originalImage imageTintedWithColor:[UIColor blueColor]];
UIButton *homeButton = [UIButton buttonWithType:UIButtonTypeCustom];
[homeButton setImage:originalImage forState:UIControlStateNormal];
[homeButton setImage:tintedImage forState:UIControlStateHighlighted];
Swift solution:
Set Default rendering mode on image (in asset catalog or from the code).
Transform the image color with this function:
extension UIImage {
public func transform(withNewColor color: UIColor) -> UIImage
{
UIGraphicsBeginImageContextWithOptions(size, false, scale)
let context = UIGraphicsGetCurrentContext()!
context.translateBy(x: 0, y: size.height)
context.scaleBy(x: 1.0, y: -1.0)
context.setBlendMode(.normal)
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
context.clip(to: rect, mask: cgImage!)
color.setFill()
context.fill(rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
}
Set transformed image to button desired state:
let redImage = image.transform(withNewColor: UIColor.red)
btn?.setImage(redImage, for: .selected)
Thanks to Rufel's answer I was able to fix my issue and reduce the code of my class at the same time:
#import "AppButton.h"
#interface AppButton ()
#property (readonly) UIImage *normalImage;
#end
#implementation AppButton
#synthesize highlightTintColor = _highlightTintColor;
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
[self initialize];
}
return self;
}
- (UIImage *)normalImage
{
return [self imageForState:UIControlStateNormal];
}
- (void)initialize
{
self.adjustsImageWhenHighlighted = NO;
// set disabled image
[self setImage:[self image:self.normalImage tintedWithColor:[UIColor colorWithRGBValue:RGBValueC9]] forState:UIControlStateDisabled];
}
- (void)setHighlightTintColor:(UIColor *)highlightTintColor
{
_highlightTintColor = highlightTintColor;
// update highlighted image
if (highlightTintColor) {
[self setImage:[self image:self.normalImage tintedWithColor:highlightTintColor] forState:UIControlStateHighlighted];
}
}
- (UIImage *)image:(UIImage *)image tintedWithColor:(UIColor *)tintColor
{
CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0f);
// Tint image
[tintColor set];
UIRectFill(rect);
[image drawInRect:rect blendMode:kCGBlendModeDestinationIn alpha:1.0f];
UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return tintedImage;
}
#end
This is a swift 3 version of rufel Answer ,
extension UIImageView {
fileprivate func tintImage(color: UIColor){
guard let _image = image else { return }
let rect = CGRect(x: 0.0, y: 0.0, width: _image.size.width , height: _image.size.height )
UIGraphicsBeginImageContextWithOptions(_image.size , false, _image.scale)
color.set()
UIRectFill(rect)
_image.draw(in: rect, blendMode: CGBlendMode.destinationIn, alpha: 1.0)
image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
}
OR
extension UIImage {
static func imageTinted(image: UIImage?, color: UIColor) -> UIImage? {
let rect = CGRect(x: 0.0, y: 0.0, width: image?.size.width ?? 0.0, height: image?.size.height ?? 0.0)
UIGraphicsBeginImageContextWithOptions(image?.size ?? CGSize.zero, false, image?.scale ?? 2.0)
color.set()
UIRectFill(rect)
image?.draw(in: rect, blendMode: CGBlendMode.destinationIn, alpha: 1.0)
let tinted = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext();
return tinted;
}
}

How can I change image tintColor

I'm receiving image from a server, then based on a color chosen by the user, the image color will be changed.
I tried the following :
_sketchImageView.image = [_sketchImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[_sketchImageView setTintColor:color];
i got the opposite of my goal (the white color outside UIImage is colored with the chosen color).
what is going wrong?
i need to do the same in this question,the provided solution doesn't solve my case.
How can I change image tintColor in iOS and WatchKit
Try to generate new image for yourself
UIImage *newImage = [_sketchImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIGraphicsBeginImageContextWithOptions(image.size, NO, newImage.scale);
[yourTintColor set];
[newImage drawInRect:CGRectMake(0, 0, image.size.width, newImage.size.height)];
newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
_sketchImageView.image = newImage;
And use it.
Good luck
======= UPDATE =======
This solution will only change color of all pixel's image.
Example: we have a book image: http://pngimg.com/upload/book_PNG2113.png
And after running above code (exp: TintColor is RED). We have:
SO: how your image is depends on how you designed it
In Swift you can use this extension: [Based on #VietHung's objective-c solution]
Swift 5:
extension UIImage {
func imageWithColor(color: UIColor) -> UIImage? {
var image = withRenderingMode(.alwaysTemplate)
UIGraphicsBeginImageContextWithOptions(size, false, scale)
color.set()
image.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
image = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
}
Previous Swift version:
extension UIImage {
func imageWithColor(color: UIColor) -> UIImage? {
var image = imageWithRenderingMode(.AlwaysTemplate)
UIGraphicsBeginImageContextWithOptions(size, false, scale)
color.set()
image.drawInRect(CGRect(x: 0, y: 0, width: size.width, height: size.height))
image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
In swift 2.0 you can use this
let image = UIImage(named:"your image name")?.imageWithRenderingMode(.AlwaysTemplate)
let yourimageView.tintColor = UIColor.redColor()
yourimageView.image = image
In swift 3.0 you can use this
let image = UIImage(named:"your image name")?.withRenderingMode(.alwaysTemplate)
let yourimageView.tintColor = UIColor.red
yourimageView.image = image
Try something like this
UIImage *originalImage = _sketchImageView.image
UIImage *newImage = [originalImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,50,50)]; // your image size
imageView.tintColor = [UIColor redColor]; // or whatever color that has been selected
imageView.image = newImage;
_sketchImageView.image = imageView.image;
Hope this helps.
In Swift 3.0 you can use this extension: [Based on #VietHung's objective-c solution]
extension UIImage {
func imageWithColor(_ color: UIColor) -> UIImage? {
var image = imageWithRenderingMode(.alwaysTemplate)
UIGraphicsBeginImageContextWithOptions(size, false, scale)
color.set()
image.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
For Swift 3.0, I made a custom subclass of UIImageView called TintedUIImageView. Now the image uses whatever tint color is set in interface builder or code
class TintedUIImageView: UIImageView {
override func awakeFromNib() {
if let image = self.image {
self.image = image.withRenderingMode(.alwaysTemplate)
}
}
}
You can try:
_sketchImageView.image = [self imageNamed:#"imageName" withColor:[UIColor blackColor]];
- (UIImage *)imageNamed:(NSString *)name withColor:(UIColor *)color
{
// load the image
//NSString *name = #"badge.png";
UIImage *img = [UIImage imageNamed:name];
// begin a new image context, to draw our colored image onto
UIGraphicsBeginImageContext(img.size);
// get a reference to that context we created
CGContextRef context = UIGraphicsGetCurrentContext();
// set the fill color
[color setFill];
// translate/flip the graphics context (for transforming from CG* coords to UI* coords
CGContextTranslateCTM(context, 0, img.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// set the blend mode to color burn, and the original image
CGContextSetBlendMode(context, kCGBlendModeColorBurn);
CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height);
CGContextDrawImage(context, rect, img.CGImage);
// set a mask that matches the shape of the image, then draw (color burn) a colored rectangle
CGContextClipToMask(context, rect, img.CGImage);
CGContextAddRect(context, rect);
CGContextDrawPath(context,kCGPathFill);
// generate a new UIImage from the graphics context we drew onto
UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return the color-burned image
return coloredImg;
}
Try setting the tint color on the superview of the image view. E.g. [self.view setTintColor:color];
in Swift 4 you can simply make an extension like that:
import UIKit
extension UIImageView {
func tintImageColor(color: UIColor) {
guard let image = image else { return }
self.image = image.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
self.tintColor = color
}
}
- SWIFT 4
extension UIImage {
func imageWithColor(_ color: UIColor) -> UIImage? {
var image: UIImage? = withRenderingMode(.alwaysTemplate)
UIGraphicsBeginImageContextWithOptions(size, false, scale)
color.set()
image?.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
Here's how I apply and use tints in IOS 9 with Swift.
//apply a color to an image
//ref - http://stackoverflow.com/questions/28427935/how-can-i-change-image-tintcolor
//ref - https://www.captechconsulting.com/blogs/ios-7-tutorial-series-tint-color-and-easy-app-theming
func getTintedImage() -> UIImageView {
var image : UIImage;
var imageView : UIImageView;
image = UIImage(named: "someAsset")!;
let size : CGSize = image.size;
let frame : CGRect = CGRectMake((UIScreen.mainScreen().bounds.width-86)/2, 600, size.width, size.height);
let redCover : UIView = UIView(frame: frame);
redCover.backgroundColor = UIColor.redColor();
redCover.layer.opacity = 0.75;
imageView = UIImageView();
imageView.image = image.imageWithRenderingMode(UIImageRenderingMode.Automatic);
imageView.addSubview(redCover);
return imageView;
}
One thing you can do is, just add your images to Assets folder in XCode and then change the rendering mode to Template Image, so whenever you change the tint color of UIImageView, it will automatically makes change to image.
Check this link out -> https://www.google.co.in/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&cad=rja&uact=8&ved=0ahUKEwiM0YXO0ejTAhUIQ48KHfGpBpgQjRwIBw&url=https%3A%2F%2Fkrakendev.io%2Fblog%2F4-xcode-asset-catalog-secrets-you-need-to-know&psig=AFQjCNGnAzVn92pCqM8612o1R0J9q1y7cw&ust=1494619445516498
let image = UIImage(named: "i m a g e n a m e")?.withRenderingMode(.alwaysTemplate)
imageView.tintColor = UIColor.white // Change to require color
imageView.image = image
Try this
iOS 13.4 and above
UIImage *image = [UIImage imageNamed:#"placeHolderIcon"];
[image imageWithTintColor:[UIColor whiteColor] renderingMode: UIImageRenderingModeAlwaysTemplate];

UISlider distorted rounded corner

I created a UISlider and then setting tint colour for min track like this :
[slider setMinimumTrackTintColor:[UIColor whiteColor]];
However I end up with distorted rounded corner on the left side like this. What do I do ?
Edit: Here is the code that reproduces the issue :
UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(40, 40, 180, 50)];
[slider setMinimumTrackTintColor:[UIColor whiteColor]];
I have experienced the same error while increasing the height of the slider.
The edges of the slider lost the rounded corners, when the height of slider increased. To fix it I created images with rounded corners and assigned it to the slider minimum track image.
Swift
override func viewDidLoad() {
super.viewDidLoad()
slider.maximumTrackTintColor = UIColor.gray;
let img:UIImage = GetImage(rectToDraw: CGRect(x: 0, y: 0, width: 400, height: 400));
slider.setMinimumTrackImage(img.resizableImage(withCapInsets: UIEdgeInsets(top: 13,left: 15,bottom: 15,right: 14)), for: UIControlState.normal)
slider.setMinimumTrackImage(img.resizableImage(withCapInsets: UIEdgeInsets(top: 13,left: 15,bottom: 15,right: 14)), for: UIControlState.selected)
}
func GetImage(rectToDraw:CGRect) -> UIImage {
let layer:CALayer = CALayer()
layer.frame = rectToDraw;
layer.cornerRadius = 20;
layer.backgroundColor = UIColor.red.cgColor;
UIGraphicsBeginImageContext(layer.frame.size)
layer.render(in: UIGraphicsGetCurrentContext()!)
let image :UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image;
}
Xamarin.iOS
Within the Custom Renderer
protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
{
MySlideriOS sliderIos = new MySlideriOS();
SetNativeControl(sliderIos);
base.OnElementChanged(e);
}
Within the Custom slider
public class MySlideriOS : UISlider
{
public UILabel label = null;
public MySlideriOS()
{
this.MaximumTrackTintColor = UIColor.Gray;
UIImage img = GetImage(new CGRect(0,0,400,400));
this.SetMinTrackImage(img.CreateResizableImage(new UIEdgeInsets(13, 15, 15,14)), UIControlState.Normal);
this.SetMinTrackImage(img.CreateResizableImage(new UIEdgeInsets(13, 15, 15, 14)), UIControlState.Selected);
this.MaxValue = 15;
}
public UIImage GetImage(CGRect recttoDraw)
{
CGRect rect = recttoDraw;
CALayer layer = new CALayer();
layer.Frame = recttoDraw;
layer.CornerRadius = 20;
layer.BackgroundColor = UIColor.Red.CGColor;
UIGraphics.BeginImageContext(layer.Frame.Size);
layer.RenderInContext(UIGraphics.GetCurrentContext());
UIImage image = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return image;
}
I've experienced the same glitch and found a solution by adding a minimumTrackImage for the slider, based on color.
UIImage *black = [UIImage imageWithColor:[UIColor blackColor]];
[self.slider setMinimumTrackImage:black forState:UIControlStateNormal];
Add a category of UIImage with the following method - imageWithColor
+ (UIImage *)imageWithColor:(UIColor *)color {
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0, 1.0);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}

How to create a circular image with border (UIGraphics)?

How to create a circular image with border (UIGraphics)?
P.S. I need to draw a picture.
code in viewDidLoad:
NSURL *url2 = [NSURL URLWithString:#"http://images.ak.instagram.com/profiles/profile_55758514_75sq_1399309159.jpg"];
NSData *data2 = [NSData dataWithContentsOfURL:url2];
UIImage *profileImg = [UIImage imageWithData:data2];
UIGraphicsEndImageContext();
// Create image context with the size of the background image.
UIGraphicsBeginImageContext(profileImg.size);
[profileImg drawInRect:CGRectMake(0, 0, profileImg.size.width, profileImg.size.height)];
// Get the newly created image.
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
// Release the context.
UIGraphicsEndImageContext();
// Set the newly created image to the imageView.
self.imageView.image = result;
It sounds like you want to clip the image to a circle. Here's an example:
static UIImage *circularImageWithImage(UIImage *inputImage,
UIColor *borderColor, CGFloat borderWidth)
{
CGRect rect = (CGRect){ .origin=CGPointZero, .size=inputImage.size };
UIGraphicsBeginImageContextWithOptions(rect.size, NO, inputImage.scale); {
// Fill the entire circle with the border color.
[borderColor setFill];
[[UIBezierPath bezierPathWithOvalInRect:rect] fill];
// Clip to the interior of the circle (inside the border).
CGRect interiorBox = CGRectInset(rect, borderWidth, borderWidth);
UIBezierPath *interior = [UIBezierPath bezierPathWithOvalInRect:interiorBox];
[interior addClip];
[inputImage drawInRect:rect];
}
UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return outputImage;
}
Result:
Have you tried this ?
self.imageView.layer.borderColor = [UIColor greenColor].CGColor;
self.imageView.layer.borderWidth = 1.f;
You'll also need
self.imageView.layer.corderRadius = self.imageView.frame.size.width/2;
self.imageView.clipsToBounds = YES;
Swift 4 version
extension UIImage {
func circularImageWithBorderOf(color: UIColor, diameter: CGFloat, boderWidth:CGFloat) -> UIImage {
let aRect = CGRect.init(x: 0, y: 0, width: diameter, height: diameter)
UIGraphicsBeginImageContextWithOptions(aRect.size, false, self.scale)
color.setFill()
UIBezierPath.init(ovalIn: aRect).fill()
let anInteriorRect = CGRect.init(x: boderWidth, y: boderWidth, width: diameter-2*boderWidth, height: diameter-2*boderWidth)
UIBezierPath.init(ovalIn: anInteriorRect).addClip()
self.draw(in: anInteriorRect)
let anImg = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return anImg
}
}

How to create a colored 1x1 UIImage on the iPhone dynamically?

I would like to create a 1x1 UIImage dynamically based on a UIColor.
I suspect this can quickly be done with Quartz2d, and I'm poring over the documentation trying to get a grasp of the fundamentals. However, it looks like there are a lot of potential pitfalls: not identifying the numbers of bits and bytes per things correctly, not specifying the right flags, not releasing unused data, etc.
How can this be safely done with Quartz 2d (or another simpler way)?
You can use CGContextSetFillColorWithColor and CGContextFillRect for this:
Swift
extension UIImage {
class func image(with color: UIColor) -> UIImage {
let rect = CGRectMake(0.0, 0.0, 1.0, 1.0)
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()
CGContextSetFillColorWithColor(context, color.CGColor)
CGContextFillRect(context, rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
Swift3
extension UIImage {
class func image(with color: UIColor) -> UIImage {
let rect = CGRect(origin: CGPoint(x: 0, y:0), size: CGSize(width: 1, height: 1))
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()!
context.setFillColor(color.cgColor)
context.fill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}
Objective-C
+ (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;
}
Here's another option based on Matt Stephen's code. It creates a resizable solid color image such that you could reuse it or change it's size (e.g. use it for a background).
+ (UIImage *)prefix_resizeableImageWithColor:(UIColor *)color {
CGRect rect = CGRectMake(0.0f, 0.0f, 3.0f, 3.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(1, 1, 1, 1)];
return image;
}
Put it in a UIImage category and change the prefix.
I used Matt Steven's answer many times so made a category for it:
#interface UIImage (mxcl)
+ (UIImage *)squareImageWithColor:(UIColor *)color dimension:(int)dimension;
#end
#implementation UIImage (mxcl)
+ (UIImage *)squareImageWithColor:(UIColor *)color dimension:(int)dimension {
CGRect rect = CGRectMake(0, 0, dimension, dimension);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
#end
Using Apple's latest UIGraphicsImageRenderer the code is pretty small:
import UIKit
extension UIImage {
static func from(color: UIColor) -> UIImage {
let size = CGSize(width: 1, height: 1)
return UIGraphicsImageRenderer(size: size).image(actions: { (context) in
context.cgContext.setFillColor(color.cgColor)
context.fill(.init(origin: .zero, size: size))
})
}
}
To me, a convenience init feels neater in Swift.
extension UIImage {
convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
UIGraphicsBeginImageContext(rect.size)
guard let context = UIGraphicsGetCurrentContext() else {
return nil
}
context.setFillColor(color.cgColor)
context.fill(rect)
guard let image = context.makeImage() else {
return nil
}
UIGraphicsEndImageContext()
self.init(cgImage: image)
}
}
Ok, this won't be exactly what you want, but this code will draw a line. You can adapt it to make a point. Or at least get a little info from it.
Making the image 1x1 seems a little weird. Strokes ride the line, so a stroke of width 1.0 at 0.5 should work. Just play around.
- (void)drawLine{
UIGraphicsBeginImageContext(CGSizeMake(320,300));
CGContextRef ctx = UIGraphicsGetCurrentContext();
float x = 0;
float xEnd = 320;
float y = 300;
CGContextClearRect(ctx, CGRectMake(5, 45, 320, 300));
CGContextSetGrayStrokeColor(ctx, 1.0, 1.0);
CGContextSetLineWidth(ctx, 1);
CGPoint line[2] = { CGPointMake(x,y), CGPointMake(xEnd, y) };
CGContextStrokeLineSegments(ctx, line, 2);
UIImage *theImage=UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}

Resources