Bagaimana cara mewarnai UIImage di Swift?

102

Saya memiliki gambar bernama arrowWhite. Saya ingin mewarnai gambar ini menjadi hitam.

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
}

Saya ingin memasukkan gambar ini blackColour.
tintColortidak bekerja...

Sujisha Os
sumber
dapat dilakukan dari Interface Builder, lihat @Harry Bloom cukup jauh di bawah
Andy Weinstein
Solusi paling elegan: stackoverflow.com/a/63167556/2692839
Umair Ali

Jawaban:

189

Swift 4 dan 5

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

Panggil seperti ini:

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

Alternativ Untuk Swift 3, 4 atau 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
        }
    }

}

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

Panggil seperti ini:

let image = UIImage(named: "your_image_name")
testImage.image =  image?.maskWithColor(color: UIColor.blue)
kuzdu
sumber
8
Awal yang bagus, tetapi hasilnya tidak jelas. Seperti yang disebutkan @Darko di bawah, saya yakin itu karena Anda tidak memperhitungkan skala dan parameter lainnya.
TruMan1
1
sama untuk saya - gambar pixelated
Async-
Prefek yang bekerja untuk saya di Swift 3. Terima kasih !!
oscar castellon
4
Tidak mempertahankan penskalaan dan orientasi.
Shailesh
di dalam ekstensi, fungsinya harus publik
Shivam Pokhriyal
88

Ada metode bawaan untuk mendapatkan UIImageyang secara otomatis ditampilkan dalam mode templat . Ini menggunakan tintColor tampilan untuk mewarnai gambar:

let templateImage = originalImage.imageWithRenderingMode(UIImageRenderingModeAlwaysTemplate)
myImageView.image = templateImage
myImageView.tintColor = UIColor.orangeColor()
Nikolai Ruhe
sumber
2
Ini adalah jawaban terbaik - info lebih lanjut dapat ditemukan di Apple Docs - developer.apple.com/library/content/documentation/…
Tandai
6
Lihat sintaks Swift 3 untuk mode rendering di sini: stackoverflow.com/a/24145287/448718
Phil_Ken_Sebben
6
menggunakan imageview sudah jelas, tapi kami ingin UIImage saja
djdance
3
bukan solusi jika Anda bekerja dengan objek UIImage secara independen dari UIImageView. Ini hanya berfungsi jika Anda memiliki akses ke UIImageView
Pez
Berfungsi hebat bahkan jika myImageView adalah UIButton
daxh
42

Pertama, Anda harus mengubah properti rendering gambar menjadi "Gambar Template" di folder .xcassets. Anda kemudian dapat mengubah properti warna tint dari instance UIImageView Anda seperti ini:

imageView.tintColor = UIColor.whiteColor()

masukkan deskripsi gambar di sini

Harry Bloom
sumber
1
Apakah tintColordihapus dari UIImagesuatu saat? Saya sangat senang dengan jawaban ini, tetapi tampaknya tidak ada di iOS 10
Travis Griggs
1
Hei @Travgs. Maaf, saya baru saja mengedit jawaban saya agar sedikit lebih deskriptif, properti tintColor ada di UIImageView, bukan UIImage
Harry Bloom
Tx, ini keren sekali! Catatan: Tint muncul di bagian View pada inspektur ImageView, sedikit lebih jauh ke bawah. Hanya untuk lebih jelasnya.
Andy Weinstein
30

Saya berakhir dengan ini karena jawaban lain kehilangan resolusi atau bekerja dengan UIImageView, bukan UIImage, atau mengandung tindakan yang tidak perlu:

Cepat 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
sumber
4
jawaban terbaik di sini, menjaga orientasi dan kualitas gambar yang sama
SmartTree
Ya, saya telah menguji semua jawaban di atas dan ini memang mempertimbangkan skala, jadi tidak akan memberi Anda pixelated UIImage. Jawaban yang sangat bagus, terima kasih!
Guilherme Matuella
21

Fungsi ini menggunakan grafik inti untuk mencapai ini.

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
sumber
8
Ini berfungsi, di mana dua jawaban teratas lainnya salah.
chrysb
4
Ya, ini bekerja dengan sempurna. maskWithColor ekstensi berfungsi tetapi mengabaikannya scalesehingga gambar tidak terlihat tajam pada perangkat resolusi tinggi.
Moin Uddin
Ini bekerja dengan sempurna !! Kami menggunakan dalam ekstensi dan berjalan OK. Solusi lain mengabaikan skala ...
Javi Campaña
17

Untuk swift 4.2 untuk mengubah warna gambar UII sesuai keinginan (warna solid)

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

Cara Penggunaan

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

Buat ekstensi di 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!
    }
}

Maka Anda bisa menggunakannya seperti itu:

image.maskWithColor(UIColor.redColor())
Darko
sumber
1
Ini mengabaikan scale, orientationdan parameter lain dari UIImage.
Nikolai Ruhe
10

Saya menemukan solusi dari HR paling membantu tetapi sedikit menyesuaikannya untuk Swift 3

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

Ini mempertimbangkan skala dan juga tidak menghasilkan gambar dengan resolusi lebih rendah seperti beberapa solusi lainnya. Penggunaan:

image = image.maskWithColor(color: .green )
Pez
sumber
Ini jelas merupakan implementasi untuk digunakan (berbeda dari yang lain di halaman ini).
Scott Corscadden
Untuk lebih amannya, bungkus paksa harus dibungkus dengan if-lets atau pelindung.
Chris Paveglio
6

Pembungkus ekstensi Swift 3 dari jawaban @Nikolai Ruhe.

extension UIImageView {

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

}

Ini bisa digunakan UIButtonjuga, misalnya:

button.imageView?.maskWith(color: .blue)
DazChong
sumber
5

Cepat 4

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

Tambahkan ekstensi ini ke kode Anda dan ubah warna gambar di papan cerita itu sendiri.

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

Pratinjau Papan Cerita:

masukkan deskripsi gambar di sini

Rajesh Loganathan
sumber
1

Cepat 3

21 Juni 2017

Saya menggunakan CALayer untuk menutupi gambar yang diberikan dengan Alpha Channel

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
sumber
1

Versi Swift 3 dengan skala dan Orientasi dari jawaban @kuzdu

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
sumber
1

Cepat 4.

Gunakan ekstensi ini untuk membuat gambar berwarna solid

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
sumber
Prefek bekerja untuk saya di navigationBar.setBackgroundImage dan Swift 5. Terima kasih!
Jesse
1

Posting iOS 13 Anda dapat menggunakannya seperti ini

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

Tambahkan Fungsi ekstensi:

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

Gunakan seperti:

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

Berikut adalah solusi HR versi 3 yang cepat.

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
sumber
-1

Karena saya menemukan jawaban Darko sangat membantu dalam mewarnai pin khusus untuk anotasi mapView, tetapi harus melakukan beberapa konversi untuk Swift 3, saya pikir saya akan membagikan kode yang diperbarui bersama dengan rekomendasi saya untuk jawabannya:

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
sumber
-2

Saya telah memodifikasi ekstensi yang ditemukan di sini: Github Gist , Swift 3yang telah saya uji dalam konteks ekstensi untuk UIImage.

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
}
98 simpanse
sumber