Crea UIImage con color sólido en Swift

140

Quiero crear mediante programación un UIImage lleno de un color sólido. ¿Alguien tiene una idea de cómo hacer esto en Swift?

Henry Pham
fuente
UIImageno tiene un -initWithSize:andColor:método, pero NSImagesí en OS X. ¿Está utilizando una biblioteca o categoría personalizada para esto?
ttarik
Lo siento, es cierto que lo usé en una categoría (mirando un proyecto antiguo). Solo edita mi pregunta.
Henry Pham

Respuestas:

194

Otra buena solución, compatible con Swift 2.2 , es crear otro constructor en UIImage, de esta manera:

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)
    }  
}

De esta manera, puede crear la imagen en color personalizada de esta manera:

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

O, opcionalmente, cree la imagen con un tamaño personalizado:

let redImage200x200 = UIImage(color: .redColor(), size: CGSize(width: 200, height: 200))

Swift 3.0

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)
  }
}
Luca Davanzo
fuente
1
si desea crear una imagen con tamaño 1x, comience con este código UIGraphicsBeginImageContextWithOptions(rect.size, true, 1.0) ref: developer.apple.com/library/ios/documentation/UIKit/Reference/…
nahung89
3
¿Cómo podemos hacer que estas imágenes sean más redondas?
Umair Afzal
¿Por qué no podemos regresar image? ¿Por qué necesitas hacer esto? self.init(cgImage: cgImage)
Andrey Gagan
@AndreyGagan AFAIK, no puedes "reemplazarte" a ti mismo con el recién creado UIImageen un constructor, pero puedes encadenarlo a través del UIImage.init(cgImage: )constructor.
Alnitak
2
La imagen no se crea con la escala adecuada. Por ejemplo, cuando el tamaño es 1x1, se devuelve una imagen 2x2 cuando la escala de la pantalla principal es 2.0. Deberías llamarself.init(cgImage: cgImage, scale: image!.scale, orientation: image!.imageOrientation)
Marián Černý
92

Aquí hay otra opción. Creo que querías un objeto UIImage exacto.

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
}

Pegue esto en su código Swift y llámelo

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
}
anthonyliao
fuente
Creo que no hay un método UIRectMake(0, 0, size.width, size.height), esto parece ser la correcta: CGRectMake(0, 0, size.width, size.height).
Henry Pham
1
En general, intente usar en letlugar de varvariables inmutables; aquí parece que rectni imagedebería usar vardeclaración.
Zorayr
1
¿Cómo podemos hacer que estas imágenes sean más redondas?
Umair Afzal
83

Versión Swift 4:

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))
        }
    }
}

Uso:

let image0 = UIColor.orange.image(CGSize(width: 128, height: 128))
let image1 = UIColor.yellow.image()
neoneye
fuente
3
Me gusta que la imagen creada no sea opcional
jlukanta
1
Esto me gusta mucho, para mí tiene mucho sentido que la extensión sea del color en lugar de la imagen.
1919
1
(⚠️ iOS 10 o más reciente). Bonita y limpia respuesta por cierto.
frouo
19

Un enfoque más limpio sería encapsular la lógica dentro de una UIImageextensión:

import UIKit

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

Ahora el consumidor puede llamar UIImage.imageWithColor(UIColor.blackColor())para crear una imagen con fondo negro.

Zorayr
fuente
¿Cómo podemos hacer que estas imágenes sean más redondas?
Umair Afzal
10
class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()

        imageView.backgroundColor = UIColor.redColor()
    }
}

Método similar si desea dibujar la imagen usted mismo versus conectar uno a través de 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)
    }
}

Tercer método tomado de anthonyliao. Un poco más complicado:

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
fuente
2
Esto probablemente se consigue que quería OP pero vale la pena nada que no tenían un método para crear una UIImage, no para establecer una UIImageView.
ttarik
Su segundo método todavía crea una vista de imagen, no una imagen, que es lo que @ ev0lution estaba señalando.
rdelmar
editar 3 adjuntos. Ahora tenemos muchas maneras. El último con un UIImageView.
Steve Rosenberg
1
El método getImageWithColor(color: UIColor, size: CGSize) -> UIImagees suficiente como respuesta, ya que creo que no todos usarán esto junto con un UIImageView
Henry Pham
¿Cómo podemos hacer que estas imágenes sean más redondas?
Umair Afzal
9

Un pequeño ajuste a la excelente respuesta de @neoneye, que permite que el código de llamada no necesite crear el CGSize, y modificó el nombre para que no choque con muchos otros:

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))
        }
    }
}
dibujó..
fuente
8

Puede usar la nueva API iOS 10 UIGraphicsImageRenderer .

Aquí hay una extensión en UIColor en 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))
    })
}}
Moustafa Baalbaki
fuente
6

Una buena manera es tener una propiedad calculada como esta:

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!
  }
}

Uso:

let redImage = UIColor.red.imageRepresentation
iOSGeek
fuente
Creo que algunas respuestas aquí son un poco engañosas. La mayoría de las veces deberá especificar el tamaño de la imagen, no un caso específico (como 1x1). Pero este es un buen enfoque.
Henry Pham el
4

Versión Swift 3 de @anthonyliao Respuesta aceptada:

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
fuente
0

Rect con esquinas redondeadas

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)
}

}

droide
fuente