Créer une UIImage avec une couleur unie dans Swift

140

Je souhaite créer par programme une UIImage remplie d'une couleur unie. Quelqu'un a-t-il une idée de comment faire cela dans Swift?

Henry Pham
la source
UIImagen'a pas de -initWithSize:andColor:méthode, mais NSImagesur OS X. Utilisez-vous une bibliothèque ou une catégorie personnalisée pour cela?
ttarik
Désolé, c'est vrai que je l'ai utilisé à travers une catégorie (en regardant un ancien projet). Modifiez simplement ma question.
Henry Pham

Réponses:

194

Une autre solution intéressante, compatible Swift 2.2 , est de créer un autre constructeur dans UIImage, de cette manière:

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 cette façon, vous pouvez créer l'image colorée personnalisée de cette manière:

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

Ou, éventuellement, créez l'image avec une taille personnalisée:

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
la source
1
si vous voulez créer une image avec une taille 1x, commencez par ce code UIGraphicsBeginImageContextWithOptions(rect.size, true, 1.0) réf: developer.apple.com/library/ios/documentation/UIKit/Reference
...
3
Comment rendre ces images plus rondes?
Umair Afzal
Pourquoi ne pouvons-nous pas simplement revenir image? Pourquoi avoir besoin de faire ça? self.init(cgImage: cgImage)
Andrey Gagan
@AndreyGagan AFAIK, vous ne pouvez pas "remplacer" self par le nouvellement créé UIImagedans un constructeur, mais vous pouvez enchaîner via le UIImage.init(cgImage: )constructeur à la place.
Alnitak
2
L'image n'est pas créée avec une échelle appropriée. Par exemple, lorsque la taille est 1x1, une image 2x2 est renvoyée lorsque l'échelle de l'écran principal est 2.0. Vous devriez appelerself.init(cgImage: cgImage, scale: image!.scale, orientation: image!.imageOrientation)
Marián Černý
92

Voici une autre option. Je crois que vous vouliez un objet UIImage exact.

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
}

Collez ceci dans votre code Swift et appelez-le

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
la source
Je pense qu'il n'y a pas de méthode UIRectMake(0, 0, size.width, size.height), cela semble être le bon: CGRectMake(0, 0, size.width, size.height).
Henry Pham
1
En règle générale, essayez d'utiliser letau lieu de varpour les variables immuables; ici semble que ni rectni imagene devrait utiliser la vardéclaration.
Zorayr
1
Comment rendre ces images plus rondes?
Umair Afzal
84

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

Usage:

let image0 = UIColor.orange.image(CGSize(width: 128, height: 128))
let image1 = UIColor.yellow.image()
neoneye
la source
3
J'aime que l'image créée ne soit pas facultative
jlukanta
1
J'aime beaucoup cela, pour moi, il est très logique que l'extension soit de couleur plutôt que d'image.
quemeful
1
(⚠️ iOS 10 ou plus récent). Réponse agréable et propre btw.
frouo
19

Une approche plus propre consisterait à encapsuler la logique à l'intérieur d'une UIImageextension:

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

Le consommateur peut désormais appeler UIImage.imageWithColor(UIColor.blackColor())pour créer une image sur fond noir.

Zorayr
la source
Comment rendre ces images plus rondes?
Umair Afzal
10
class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()

        imageView.backgroundColor = UIColor.redColor()
    }
}

Méthode similaire si vous voulez dessiner l'image vous-même ou en connecter une 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)
    }
}

Troisième méthode empruntant à anthonyliao. Un peu plus compliqué:

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
la source
2
Cela produit probablement l'effet recherché par OP, mais cela ne vaut rien qu'ils aient une méthode pour créer un UIImage, pas pour définir un UIImageView.
ttarik
Votre deuxième méthode crée toujours une vue d'image, pas une image, ce que @ ev0lution soulignait.
rdelmar
modifier 3 ci-joint. Maintenant, nous avons un tas de moyens. Le dernier avec un UIImageView.
Steve Rosenberg
1
La méthode getImageWithColor(color: UIColor, size: CGSize) -> UIImageest suffisante comme réponse, car je pense que tout le monde ne l'utilisera pas avec une UIImageView
Henry Pham
Comment rendre ces images plus rondes?
Umair Afzal
9

Une modification mineure de l'excellente réponse de @ neoneye, permettant au code appelant de ne pas avoir besoin de créer le CGSize, et a modifié le nom pour ne pas entrer en collision avec de nombreux autres:

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))
        }
    }
}
a dessiné..
la source
8

Vous pouvez utiliser la nouvelle API UIGraphicsImageRenderer iOS 10 .

Voici une extension sur UIColor dans 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
la source
6

Une bonne façon est d'avoir une propriété calculée comme celle-ci:

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
la source
Je pense que certaines réponses ici sont un peu trompeuses. La plupart du temps, vous devrez spécifier la taille de l'image, pas un cas spécifique (comme 1x1). Mais c'est une belle approche.
Henry Pham
4

Version Swift 3 de @anthonyliao Réponse acceptée:

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
la source
0

Rect avec coins arrondis

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

}

droïde
la source