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


dapat dilakukan dari Interface Builder, lihat @Harry Bloom cukup jauh di bawah
Andy Weinstein

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)

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

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


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
    }

}

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
}

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)

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

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 )

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)

5

Cepat 4

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

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



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

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

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

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)

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)

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
}

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

-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
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.