Wie kann ich ein UIImage in Swift ausmalen?

101

Ich habe ein Bild namens arrowWhite. Ich möchte dieses Bild schwarz färben.

func attachDropDownArrow() -> NSMutableAttributedString {
    let image:UIImage = UIImage(named: "arrowWhite.png")!
    let attachment = NSTextAttachment()
    attachment.image = image
    attachment.bounds = CGRectMake(2.25, 2, attachment.image!.size.width - 2.25, attachment.image!.size.height - 2.25)
    let attachmentString = NSAttributedString(attachment: attachment)
    let myString = NSMutableAttributedString(string: NSString(format: "%@", self.privacyOptions[selectedPickerRow]) as String)
    myString.appendAttributedString(attachmentString)
    return myString
}

Ich möchte dieses Bild aufnehmen blackColour.
tintColorfunktioniert nicht...

Sujisha Os
quelle
machbar mit dem Interface Builder, siehe @Harry Bloom ziemlich weit unten
Andy Weinstein
Die eleganteste Lösung: stackoverflow.com/a/63167556/2692839
Umair Ali

Antworten:

187

Swift 4 und 5

extension UIImageView {
  func setImageColor(color: UIColor) {
    let templateImage = self.image?.withRenderingMode(.alwaysTemplate)
    self.image = templateImage
    self.tintColor = color
  }
}

Rufen Sie so an:

let imageView = UIImageView(image: UIImage(named: "your_image_name"))
imageView.setImageColor(color: UIColor.purple)

Alternativ für Swift 3, 4 oder 5

extension UIImage {

    func maskWithColor(color: UIColor) -> UIImage? {
        let maskImage = cgImage!

        let width = size.width
        let height = size.height
        let bounds = CGRect(x: 0, y: 0, width: width, height: height)

        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
        let context = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)!

        context.clip(to: bounds, mask: maskImage)
        context.setFillColor(color.cgColor)
        context.fill(bounds)

        if let cgImage = context.makeImage() {
            let coloredImage = UIImage(cgImage: cgImage)
            return coloredImage
        } else {
            return nil
        }
    }

}

Für Swift 2.3

extension UIImage {
func maskWithColor(color: UIColor) -> UIImage? {

    let maskImage = self.CGImage
    let width = self.size.width
    let height = self.size.height
    let bounds = CGRectMake(0, 0, width, height)

    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedLast.rawValue)
    let bitmapContext = CGBitmapContextCreate(nil, Int(width), Int(height), 8, 0, colorSpace, bitmapInfo.rawValue) //needs rawValue of bitmapInfo

    CGContextClipToMask(bitmapContext, bounds, maskImage)
    CGContextSetFillColorWithColor(bitmapContext, color.CGColor)
    CGContextFillRect(bitmapContext, bounds)

    //is it nil?
    if let cImage = CGBitmapContextCreateImage(bitmapContext) {
        let coloredImage = UIImage(CGImage: cImage)

        return coloredImage

    } else {
        return nil
    } 
 }
}

Rufen Sie so an:

let image = UIImage(named: "your_image_name")
testImage.image =  image?.maskWithColor(color: UIColor.blue)
Kuzdu
quelle
8
Schöner Start, aber das Ergebnis ist körnig. Wie @Darko weiter unten erwähnt, liegt dies meines Erachtens daran, dass Sie die Skalierung und andere Parameter nicht berücksichtigen.
TruMan1
1
Gleiches gilt für mich -
Pixelbild
Arbeitete Präfekt für mich in Swift 3. Danke !!
Oscar Castellon
4
Bewahrt Skalierung und Ausrichtung nicht.
Shailesh
Innerhalb der Erweiterung sollte die Funktion öffentlich sein
Shivam Pokhriyal
88

Es gibt eine integrierte Methode, um eine zu erhalten UIImage, die automatisch im Vorlagenmodus gerendert wird . Dies verwendet die Farbe tintColor einer Ansicht, um das Bild einzufärben:

let templateImage = originalImage.imageWithRenderingMode(UIImageRenderingModeAlwaysTemplate)
myImageView.image = templateImage
myImageView.tintColor = UIColor.orangeColor()
Nikolai Ruhe
quelle
2
Dies ist die beste Antwort - weitere Informationen können in Apple - Docs finden - developer.apple.com/library/content/documentation/...
Mark
6
Siehe Swift 3 Syntax für den Rendermodus hier: stackoverflow.com/a/24145287/448718
Phil_Ken_Sebben
6
Die Verwendung von imageview ist offensichtlich, aber wir wollen nur
UIImage
3
Keine Lösung, wenn Sie mit UIImage-Objekten unabhängig von UIImageViews arbeiten. Dies funktioniert nur, wenn Sie Zugriff auf UIImageView
Pez
Funktioniert auch dann hervorragend, wenn myImageView ein UIButton ist
daxh
42

Zuerst müssen Sie die Rendering-Eigenschaft des Bildes im Ordner ".xcassets" in "Vorlagenbild" ändern. Sie können dann einfach die Farbton-Farbeigenschaft der Instanz Ihres UIImageView folgendermaßen ändern:

imageView.tintColor = UIColor.whiteColor()

Geben Sie hier die Bildbeschreibung ein

Harry Bloom
quelle
1
Haben tintColorerhalten von entfernt UIImageirgendwann? Ich war begeistert von dieser Antwort, aber sie scheint in iOS 10 nicht zu existieren
Travis Griggs
1
Hey @TravisGriggs. Entschuldigung, ich habe meine Antwort so bearbeitet, dass sie etwas aussagekräftiger ist. Die Eigenschaft tintColor befindet sich in UIImageView, nicht in UIImage
Harry Bloom,
Tx, das ist so cool! Hinweis: Der Farbton wird im Abschnitt "Ansicht" des ImageView-Inspektors etwas weiter unten angezeigt. Nur um ganz klar zu sein.
Andy Weinstein
29

Ich bin dazu gekommen, weil andere Antworten entweder die Auflösung verlieren oder mit UIImageView arbeiten, nicht mit UIImage, oder unnötige Aktionen enthalten:

Swift 3

extension UIImage {

    public func maskWithColor(color: UIColor) -> UIImage {

        UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
        let context = UIGraphicsGetCurrentContext()!

        let rect = CGRect(origin: CGPoint.zero, size: size)

        color.setFill()
        self.draw(in: rect)

        context.setBlendMode(.sourceIn)
        context.fill(rect)

        let resultImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return resultImage
    }

}
Alex Shubin
quelle
4
beste Antwort hier, behält die gleiche
Bildausrichtung
Ja, ich habe alle oben genannten Antworten getestet und dies berücksichtigt in der Tat die Skala, sodass Sie keine pixeligen UIImages erhalten. Wirklich schöne Antwort, danke!
Guilherme Matuella
21

Diese Funktion verwendet Kerngrafiken, um dies zu erreichen.

func overlayImage(color: UIColor) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(self.size, false, UIScreen.main.scale)
    let context = UIGraphicsGetCurrentContext()

    color.setFill()

    context!.translateBy(x: 0, y: self.size.height)
    context!.scaleBy(x: 1.0, y: -1.0)

    context!.setBlendMode(CGBlendMode.colorBurn)
    let rect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)
    context!.draw(self.cgImage!, in: rect)

    context!.setBlendMode(CGBlendMode.sourceIn)
    context!.addRect(rect)
    context!.drawPath(using: CGPathDrawingMode.fill)

    let coloredImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return coloredImage
}
HR
quelle
8
Dies funktioniert, wenn die beiden anderen Antworten falsch sind.
Chrysb
4
Ja das funktioniert perfekt. maskWithColor Die Erweiterung funktioniert, wird jedoch ignoriert, scalesodass das Bild auf Geräten mit höherer Auflösung nicht scharf aussieht.
Moin Uddin
Das funktioniert perfekt !! Wir verwenden in einer Erweiterung und läuft OK. Andere Lösungen ignorieren Skalierung ...
Javi Campaña
17

Damit Swift 4.2 die UIImage-Farbe nach Belieben ändert (Volltonfarbe)

extension UIImage {
    func imageWithColor(color: UIColor) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
        color.setFill()

        let context = UIGraphicsGetCurrentContext()
        context?.translateBy(x: 0, y: self.size.height)
        context?.scaleBy(x: 1.0, y: -1.0)
        context?.setBlendMode(CGBlendMode.normal)

        let rect = CGRect(origin: .zero, size: CGSize(width: self.size.width, height: self.size.height))
        context?.clip(to: rect, mask: self.cgImage!)
        context?.fill(rect)

        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage!
    }
}

Wie benutzt man

self.imgVw.image = UIImage(named: "testImage")?.imageWithColor(UIColor.red)
Hardik Thakkar
quelle
10

Erstellen Sie eine Erweiterung in UIImage:

/// UIImage Extensions
extension UIImage {
    func maskWithColor(color: UIColor) -> UIImage {

        var maskImage = self.CGImage
        let width = self.size.width
        let height = self.size.height
        let bounds = CGRectMake(0, 0, width, height)

        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo = CGBitmapInfo(CGImageAlphaInfo.PremultipliedLast.rawValue)
        let bitmapContext = CGBitmapContextCreate(nil, Int(width), Int(height), 8, 0, colorSpace, bitmapInfo)

        CGContextClipToMask(bitmapContext, bounds, maskImage)
        CGContextSetFillColorWithColor(bitmapContext, color.CGColor)
        CGContextFillRect(bitmapContext, bounds)

        let cImage = CGBitmapContextCreateImage(bitmapContext)
        let coloredImage = UIImage(CGImage: cImage)

        return coloredImage!
    }
}

Dann können Sie es so verwenden:

image.maskWithColor(UIColor.redColor())
Darko
quelle
1
Dabei wird übersehen scale, orientationund andere Parameter UIImage.
Nikolai Ruhe
10

Ich fand die Lösung von HR am hilfreichsten, passte sie jedoch leicht an Swift 3 an

extension UIImage {

    func maskWithColor( color:UIColor) -> UIImage {

         UIGraphicsBeginImageContextWithOptions(self.size, false, UIScreen.main.scale)
         let context = UIGraphicsGetCurrentContext()!

         color.setFill()

         context.translateBy(x: 0, y: self.size.height)
         context.scaleBy(x: 1.0, y: -1.0)

         let rect = CGRect(x: 0.0, y: 0.0, width: self.size.width, height: self.size.height)
         context.draw(self.cgImage!, in: rect)

         context.setBlendMode(CGBlendMode.sourceIn)
         context.addRect(rect)
         context.drawPath(using: CGPathDrawingMode.fill)

         let coloredImage = UIGraphicsGetImageFromCurrentImageContext()
         UIGraphicsEndImageContext()

         return coloredImage!
    }
}

Dies berücksichtigt die Skalierung und erzeugt auch kein Bild mit niedrigerer Auflösung wie bei einigen anderen Lösungen. Verwendung :

image = image.maskWithColor(color: .green )
Pez
quelle
Dies ist definitiv die zu verwendende Implementierung (Unterscheidung von anderen auf dieser Seite).
Scott Corscadden
Um besonders sicher zu sein, sollten die Kraftabwicklungen in If-Lets oder eine Wache eingewickelt werden.
Chris Paveglio
5

Swift 3 Extension Wrapper von @Nikolai Ruhe antworten.

extension UIImageView {

    func maskWith(color: UIColor) {
        guard let tempImage = image?.withRenderingMode(.alwaysTemplate) else { return }
        image = tempImage
        tintColor = color
    }

}

Es kann auch verwendet werden für UIButtonz.

button.imageView?.maskWith(color: .blue)
DazChong
quelle
4

Swift 4

 let image: UIImage? =  #imageLiteral(resourceName: "logo-1").withRenderingMode(.alwaysTemplate)
    topLogo.image = image
    topLogo.tintColor = UIColor.white
Alfi
quelle
4

Fügen Sie diese Erweiterung in Ihren Code ein und ändern Sie die Bildfarbe im Storyboard.

Swift 4 & 5:

extension UIImageView {
    @IBInspectable
    var changeColor: UIColor? {
        get {
            let color = UIColor(cgColor: layer.borderColor!);
            return color
        }
        set {
            let templateImage = self.image?.withRenderingMode(.alwaysTemplate)
            self.image = templateImage
            self.tintColor = newValue
        }
    }
}

Storyboard-Vorschau:

Geben Sie hier die Bildbeschreibung ein

Rajesh Loganathan
quelle
1

Swift 3 Version mit Skalierung und Orientierung von @kuzdu Antwort

extension UIImage {

    func mask(_ color: UIColor) -> UIImage? {
        let maskImage = cgImage!

        let width = (cgImage?.width)!
        let height = (cgImage?.height)!
        let bounds = CGRect(x: 0, y: 0, width: width, height: height)

        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
        let context = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)!

        context.clip(to: bounds, mask: maskImage)
        context.setFillColor(color.cgColor)
        context.fill(bounds)

        if let cgImage = context.makeImage() {
            let coloredImage = UIImage.init(cgImage: cgImage, scale: scale, orientation: imageOrientation)
            return coloredImage
        } else {
            return nil
        }
    }
}
Shailesh
quelle
1

Swift 4.

Verwenden Sie diese Erweiterung, um ein einfarbiges Bild zu erstellen

extension UIImage {   

    public func coloredImage(color: UIColor) -> UIImage? {
        return coloredImage(color: color, size: CGSize(width: 1, height: 1))
    }

    public func coloredImage(color: UIColor, size: CGSize) -> UIImage? {

        UIGraphicsBeginImageContextWithOptions(size, false, 0)

        color.setFill()
        UIRectFill(CGRect(origin: CGPoint(), size: size))

        guard let image = UIGraphicsGetImageFromCurrentImageContext() else { return nil }
        UIGraphicsEndImageContext()

        return image
    }
}
Khemmachart Chutapetch
quelle
Arbeitete Präfekt für mich in NavigationBar.setBackgroundImage und Swift 5. Danke!
Jesse
1

Nach iOS 13 können Sie es so etwas verwenden

arrowWhiteImage.withTintColor(.black, renderingMode: .alwaysTemplate)
Sanjeevcn
quelle
1

Erweiterung hinzufügen Funktion:

extension UIImageView {
    func setImage(named: String, color: UIColor) {
        self.image = #imageLiteral(resourceName: named).withRenderingMode(.alwaysTemplate)
        self.tintColor = color
    }
}

Verwenden Sie wie:

anyImageView.setImage(named: "image_name", color: .red)
Ngima Sherpa
quelle
0

Hier ist die schnelle 3-Version der HR-Lösung.

func overlayImage(color: UIColor) -> UIImage? {
    UIGraphicsBeginImageContextWithOptions(self.size, false, UIScreen.main.scale)
    let context = UIGraphicsGetCurrentContext()

    color.setFill()

    context!.translateBy(x: 0, y: self.size.height)
    context!.scaleBy(x: 1.0, y: -1.0)

    context!.setBlendMode(CGBlendMode.colorBurn)
    let rect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)
    context!.draw(self.cgImage!, in: rect)

    context!.setBlendMode(CGBlendMode.sourceIn)
    context!.addRect(rect)
    context!.drawPath(using: CGPathDrawingMode.fill)

    let coloredImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return coloredImage
}
Moin Uddin
quelle
0

Swift 3

21. Juni 2017

Ich benutze CALayer, um das gegebene Bild mit Alpha Channel zu maskieren

import Foundation


extension UIImage {

    func maskWithColor(color: UIColor) -> UIImage? {
    
        let maskLayer = CALayer()
        maskLayer.bounds = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        maskLayer.backgroundColor = color.cgColor
        maskLayer.doMask(by: self)
        let maskImage = maskLayer.toImage()
        return maskImage
    }

}


extension CALayer {
    func doMask(by imageMask: UIImage) {
        let maskLayer = CAShapeLayer()
        maskLayer.bounds = CGRect(x: 0, y: 0, width: imageMask.size.width, height: imageMask.size.height)
        bounds = maskLayer.bounds
        maskLayer.contents = imageMask.cgImage
        maskLayer.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height)
        mask = maskLayer
    }

    func toImage() -> UIImage?
    {
        UIGraphicsBeginImageContextWithOptions(bounds.size,
                                               isOpaque,
                                               UIScreen.main.scale)
        guard let context = UIGraphicsGetCurrentContext() else {
            UIGraphicsEndImageContext()
            return nil
        }
        render(in: context)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}
Yi Jiang
quelle
-1

Da ich Darkos Antwort beim Färben von benutzerdefinierten Pins für mapView-Anmerkungen sehr hilfreich fand, aber einige Konvertierungen für Swift 3 vornehmen musste, dachte ich, ich würde den aktualisierten Code zusammen mit meiner Empfehlung für seine Antwort teilen:

extension UIImage {
    func maskWithColor(color: UIColor) -> UIImage {

        var maskImage = self.CGImage
        let width = self.size.width
        let height = self.size.height
        let bounds = CGRect(x: 0, y: 0, width: width, height: height)

        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
        let bitmapContext = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)

        bitmapContext!.clip(to: bounds, mask: maskImage!)
        bitmapContext!.setFillColor(color.cgColor)
        bitmapContext!.fill(bounds)

        let cImage = bitmapContext!.makeImage()
        let coloredImage = UIImage(CGImage: cImage)

        return coloredImage!
    }
}
Ron Diel
quelle
-2

Ich habe die hier gefundene Erweiterung geändert: Github Gist , für Swift 3die ich im Rahmen einer Erweiterung für UIImage getestet habe.

func tint(with color: UIColor) -> UIImage 
{
   UIGraphicsBeginImageContext(self.size)
   guard let context = UIGraphicsGetCurrentContext() else { return self }

   // flip the image
   context.scaleBy(x: 1.0, y: -1.0)
   context.translateBy(x: 0.0, y: -self.size.height)

   // multiply blend mode
   context.setBlendMode(.multiply)

   let rect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)
   context.clip(to: rect, mask: self.cgImage!)
   color.setFill()
   context.fill(rect)

   // create UIImage
   guard let newImage = UIGraphicsGetImageFromCurrentImageContext() else { return self }
   UIGraphicsEndImageContext()

   return newImage
}
98chimp
quelle