184

I want to programmatically create an UIImage filled by a solid color. Anyone have an idea of how to do this in Swift?

Henry Pham
  • 2,429
  • 3
  • 19
  • 19
  • `UIImage` doesn't have an `-initWithSize:andColor:` method, but `NSImage` does on OS X. Are you using a custom library or category for this? – ttarik Oct 24 '14 at 05:35
  • Sorry, it's true that I used it through a category (looking at an old project). Just edit my question. – Henry Pham Oct 24 '14 at 11:23

15 Answers15

245

Another nice solution, Swift 3.0

    public extension UIImage {
      convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
        let rect = CGRect(origin: .zero, size: size)
        UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
        color.setFill()
        UIRectFill(rect)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        guard let cgImage = image?.cgImage else { return nil }
        self.init(cgImage: cgImage)
      }
    }

Swift 2.2 compatible, is to create another constructor in UIImage, in this way:

    public extension UIImage {
        public convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
            let rect = CGRect(origin: .zero, size: size)
            UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
            color.setFill()
            UIRectFill(rect)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
        
            guard let cgImage = image?.CGImage else { return nil }
            self.init(CGImage: cgImage)
        }  
    }

In this way you can create the custom colored-image in this way:

    let redImage = UIImage(color: .redColor())

Or, optionally, create the image with a custom size:

    let redImage200x200 = UIImage(color: .redColor(), size: CGSize(width: 200, height: 200))
Alexander Volkov
  • 7,904
  • 1
  • 47
  • 44
Luca Davanzo
  • 21,000
  • 15
  • 120
  • 146
  • 1
    if you want to create image with 1x size, start with this code `UIGraphicsBeginImageContextWithOptions(rect.size, true, 1.0)` ref: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIKitFunctionReference/#//apple_ref/c/func/UIGraphicsBeginImageContextWithOptions – nahung89 Jan 20 '16 at 04:03
  • 3
    How can we make these images rounder corner ? – Umair Afzal Dec 05 '16 at 07:02
  • Why we can't just return `image`? Why need to do this? `self.init(cgImage: cgImage)` – Andrey Gagan Jan 24 '17 at 12:49
  • @AndreyGagan AFAIK, you can't "replace" self with the newly created `UIImage` in a constructor, but you can chain via the `UIImage.init(cgImage: )` constructor instead. – Alnitak Mar 11 '17 at 15:17
  • 4
    The image is not created with proper scale. E.g. when the size is 1x1, an image 2x2 is returned when the main screen scale is 2.0. You should call `self.init(cgImage: cgImage, scale: image!.scale, orientation: image!.imageOrientation)` – Marián Černý Oct 20 '17 at 12:06
  • Use `UIGraphicsImageRenderer` – onmyway133 Apr 12 '19 at 10:53
157

Swift 4 version:

extension UIColor {
    func image(_ size: CGSize = CGSize(width: 1, height: 1)) -> UIImage {
        return UIGraphicsImageRenderer(size: size).image { rendererContext in
            self.setFill()
            rendererContext.fill(CGRect(origin: .zero, size: size))
        }
    }
}

Usage:

let image0 = UIColor.orange.image(CGSize(width: 128, height: 128))
let image1 = UIColor.yellow.image()
kasyanov-ms
  • 431
  • 4
  • 12
neoneye
  • 50,398
  • 25
  • 166
  • 151
93

Here's another option. I believe you wanted an exact UIImage object.

func getImageWithColor(color: UIColor, size: CGSize) -> UIImage {
    let rect = CGRectMake(0, 0, size.width, size.height)
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    color.setFill()
    UIRectFill(rect)
    let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image
}

Stick this in your Swift code and call it

Swift 3.1:

func getImageWithColor(color: UIColor, size: CGSize) -> UIImage {
    let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    color.setFill()
    UIRectFill(rect)
    let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return image
}
Adrian
  • 16,233
  • 18
  • 112
  • 180
anthonyliao
  • 1,314
  • 1
  • 8
  • 8
  • I think there is no method `UIRectMake(0, 0, size.width, size.height)`, this seems to be the correct one: `CGRectMake(0, 0, size.width, size.height)`. – Henry Pham Oct 24 '14 at 10:52
  • 1
    Generally, try to use `let` instead of `var` for immutable variables; here seems like neither `rect` nor `image` should be using `var` declaration. – Zorayr Apr 26 '15 at 00:37
  • 1
    How can we make these images rounder corner ? – Umair Afzal Dec 05 '16 at 07:02
27

A cleaner approach would be to encapsulate the logic inside an UIImage extension:

import UIKit

extension UIImage {
  class func imageWithColor(color: UIColor) -> UIImage {
    let rect: CGRect = CGRect(x: 0, y: 0, width: 1, height: 1)
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(1, 1), false, 0)
    color.setFill()
    UIRectFill(rect)
    let image: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image!
  }
}

Now the consumer can call, UIImage.imageWithColor(UIColor.blackColor()) to create an image with black background.

andy0570
  • 574
  • 5
  • 13
Zorayr
  • 23,770
  • 8
  • 136
  • 129
14

A minor tweak to @neoneye's excellent answer, allowing the calling code not to need to create the CGSize, and altered the name to not collide with numerous others:

Swift 4

extension UIColor {
    func imageWithColor(width: Int, height: Int) -> UIImage {
        let size = CGSize(width: width, height: height)
        return UIGraphicsImageRenderer(size: size).image { rendererContext in
            self.setFill()
            rendererContext.fill(CGRect(origin: .zero, size: size))
        }
    }
}
drew..
  • 3,234
  • 3
  • 16
  • 19
10
class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()

        imageView.backgroundColor = UIColor.redColor()
    }
}

Similar method if you want draw the image yourself vs. connecting one via IBOutlet.

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        var frame = CGRectMake(100,100,100,100)
        var imageView2 = UIImageView(frame: frame)
        imageView2.backgroundColor = UIColor.redColor()
        self.view.addSubview(imageView2)
    }
}

Third method borrowing from anthonyliao. A little more complicated:

class ViewController: UIViewController {

    func getImageWithColor(color: UIColor, size: CGSize) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, 0)
        color.setFill()
        UIRectFill(CGRectMake(0, 0, 100, 100))
        var image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        var imageView = UIImageView(frame: CGRectMake(100,100,100,100))
        let screenImage = getImageWithColor(UIColor.redColor(), size: CGSize(width: 100, height: 100))
        imageView.image = screenImage
        self.view.addSubview(imageView)
    }
}
Steve Rosenberg
  • 19,348
  • 7
  • 46
  • 53
  • 2
    This *probably* achieves the effect that OP wanted but it's worth nothing that they had a method to create a `UIImage`, not to set a `UIImageView`. – ttarik Oct 24 '14 at 05:41
  • Your second method still creates an image view, not an image, which is what @ev0lution was pointing out. – rdelmar Oct 24 '14 at 05:53
  • edit 3 attached. Now we have a bunch of ways. Final one with a UIImageView. – Steve Rosenberg Oct 24 '14 at 06:18
  • 1
    The method `getImageWithColor(color: UIColor, size: CGSize) -> UIImage` is enough as the answer, as I think not everyone will use this together with an UIImageView – Henry Pham Oct 24 '14 at 11:07
  • How can we make these images rounder corner ? – Umair Afzal Dec 05 '16 at 07:03
8

You can use the new iOS 10 UIGraphicsImageRenderer API.

Here is an extension on UIColor in Swift 3.1

extension UIColor {
func getImage(size: CGSize) -> UIImage {
    let renderer = UIGraphicsImageRenderer(size: size)
    return renderer.image(actions: { rendererContext in
        self.setFill()
        rendererContext.fill(CGRect(x: 0, y: 0, width: size.width, height: size.height))
    })
}}
7

A nice way is to have a computed property like this:

extension UIColor {
    var imageRepresentation : UIImage {
      let rect = CGRect(x: 0.0, y: 0.0, width: 1.0, height: 1.0)
      UIGraphicsBeginImageContext(rect.size)
      let context = UIGraphicsGetCurrentContext()

      context?.setFillColor(self.cgColor)
      context?.fill(rect)

      let image = UIGraphicsGetImageFromCurrentImageContext()
      UIGraphicsEndImageContext()

    return image!
  }
}

Usage:

let redImage = UIColor.red.imageRepresentation
iOSGeek
  • 5,115
  • 9
  • 46
  • 74
  • I think some answers here are a little misleading. Most of the time you will need to specify the size of the image, not a specific case (like 1x1). But this is a nice approach. – Henry Pham Aug 24 '17 at 09:11
4

Swift 3 version of @anthonyliao Accepted answer:

class func getImageWithColor(color: UIColor, size: CGSize) -> UIImage
{
    let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: size.width, height: size.height))
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    color.setFill()
    UIRectFill(rect)
    let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return image
}
Ayman Ibrahim
  • 1,359
  • 15
  • 24
4

Swift 5, Xcode 12.4 - UIImageView's solution

If you have to deal with UIImageViews like in my case, you could opt for a more compact solution like: exampleImageView.fill() or exampleImageView.fill(with: .black).

Extension's code:

extension UIImageView {
    func fill(with color: UIColor = .lightGray) {
        let size = self.bounds.size
        let image = UIGraphicsImageRenderer(size: size).image { rendererContext in
            color.setFill()
            rendererContext.fill(CGRect(origin: .zero, size: size))
        }
        self.image = image
    }
}
Alessandro Francucci
  • 1,528
  • 17
  • 25
3

Rect with rounded corners

extension UIImage {
    convenience init?(color: UIColor) {
        let rect = CGRect(x: 0, y: 0, width: 10, height: 2)
        UIGraphicsBeginImageContextWithOptions(CGSize(width: 10, height: 2), false, 0)
        let bezierPath = UIBezierPath(roundedRect: rect, cornerRadius: 8)
        color.setFill()
        bezierPath.fill()
        let image = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        
        guard  let cgImage = image.cgImage else {
            return nil
        }
        self.init(cgImage: cgImage)
    }
}
LondonGuy
  • 10,778
  • 11
  • 79
  • 151
droid
  • 581
  • 7
  • 16
2

Swift 5 / Get not optional UIImage

  public static func withColor(_ color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) -> UIImage {
        let format = UIGraphicsImageRendererFormat()
        format.scale = 1
        let image =  UIGraphicsImageRenderer(size: size, format: format).image { rendererContext in
            color.setFill()
            rendererContext.fill(CGRect(origin: .zero, size: size))
        }
        return image
    }

Don't forget to use format.scale = 1 if it needed

  • 1
    Welcome to StackOverflow Mikhail. While your code example may solve the question an explanation of how and why this solves the problem would really help to improve the quality of your answer. Remember that you're answering the question for readers in the future, not just the person asking now. I suggest you add an explanation to your answer. You might find the [How do I write a good answer](https://stackoverflow.com/help/how-to-answer) article helpful. – Mike Poole Jan 14 '21 at 14:32
  • Works great! Used it to set the background color of a UISegmentedControl(), wherein they don't provide API to do it through .backgroundColor or other means, and this did the trick. Thanks! – clearlight Apr 04 '23 at 10:39
2

2023. Honestly it's this simple!

let image = UIGraphicsImageRenderer(size: sz).image { rendererContext in
    UIColor.gray.setFill()
    rendererContext.fill(CGRect(origin: .zero, size: sz))
}
Fattie
  • 27,874
  • 70
  • 431
  • 719
1

we can use UIGraphicsImageRenderer to create the UIImage or use traditional CGContext approach, below is convenience init function which creates UIImage with given color

extension UIImage {
    /// create UIImage with color and given size
    convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1), alpha: CGFloat = 1, scale: CGFloat = 0) {
        if #available(tvOS 10.0, *) {
            let renderer = UIGraphicsImageRenderer(size: size)
            let image = renderer.image { (ctx) in
                let size = renderer.format.bounds.size
                ctx.fill(CGRect(origin: .zero, size: size))
                ctx.cgContext.setFillColor(color.cgColor)
            }
            guard let cgImage = image.cgImage else { return nil }
            self.init(cgImage: cgImage)
        } else {
            let rect = CGRect(origin: .zero, size: size)
            UIGraphicsBeginImageContextWithOptions(rect.size, false, scale)
            let context = UIGraphicsGetCurrentContext()!
            let fillColor = color.withAlphaComponent(alpha)
            context.setFillColor(fillColor.cgColor)
            context.fill(rect)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            guard let cgImage = image?.cgImage else { return nil }
            self.init(cgImage: cgImage)
        }
    }
}
Suhit Patil
  • 11,748
  • 3
  • 50
  • 60
1

If your application support iOS 10 or above, we should use UIGraphicsImageRenderer since it is faster.

Here are some static methods / init methods (optional UIImage) in UIImage's extension:

import UIKit

extension UIImage {
    static func from(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) -> UIImage {
        let format = UIGraphicsImageRendererFormat()
        format.scale = 1
        return UIGraphicsImageRenderer(size: size, format: format).image { context in
            color.setFill()
            context.fill(CGRect(origin: .zero, size: size))
        }
    }

    static func from(color: UIColor, size: CGFloat = 1) -> UIImage {
        return from(color: color, size: CGSize(width: size, height: size))
    }

    static func from(color: UIColor) -> UIImage {
        return from(color: color, size: 1)
    }

    convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
        let format = UIGraphicsImageRendererFormat()
        format.scale = 1
        let image = UIGraphicsImageRenderer(size: size, format: format).image { context in
            color.setFill()
            context.fill(CGRect(origin: .zero, size: size))
        }
        guard let cgImage = image.cgImage else { return nil }
        self.init(cgImage: cgImage)
    }

    convenience init?(color: UIColor, size: CGFloat = 1) {
        self.init(color: color, size: CGSize(width: size, height: size))
    }

    convenience init?(color: UIColor) {
        self.init(color: color, size: 1)
    }
}

struct Example {
    func createAnImageWithColorRed() {
        UIImage(color: .red, size: CGSize(width: 10, height: 10))
        UIImage(color: .red, size: 10)
        UIImage(color: .red)

        UIImage.from(color: .red, size: CGSize(width: 10, height: 10))
        UIImage.from(color: .red, size: 10)
        UIImage.from(color: .red)
    }
}

Preview:

enter image description here

Chris So
  • 711
  • 1
  • 11
  • 23