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


machbar mit dem Interface Builder, siehe @Harry Bloom ziemlich weit unten
Andy Weinstein

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)

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

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


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
    }

}

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
}

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)

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

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 )

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)

4

Swift 4

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

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



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

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

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)

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)

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
}

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

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

-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
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.