Làm cách nào để tô màu UIImage trong Swift?


101

Tôi có một hình ảnh được gọi là arrowWhite. Tôi muốn tô màu hình ảnh này thành màu đen.

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
}

Tôi muốn đưa hình ảnh này vào blackColour.
tintColorkhông hoạt động...


có thể thực hiện được từ Trình tạo giao diện, xem @Harry Bloom khá xa bên dưới
Andy Weinstein

Giải pháp thanh lịch nhất: stackoverflow.com/a/63167556/2692839
Umair Ali

Câu trả lời:


188

Swift 4 và 5

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

Gọi như thế này:

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

Alternativ dành cho Swift 3, 4 hoặc 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
        }
    }

}

Đối với 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
    } 
 }
}

Gọi như thế này:

let image = UIImage(named: "your_image_name")
testImage.image =  image?.maskWithColor(color: UIColor.blue)

8
Khởi đầu tốt đẹp, nhưng kết quả là không tốt. Như @Darko đề cập bên dưới, tôi tin rằng đó là do bạn không tính đến quy mô và các thông số khác.
TruMan1

1
tương tự đối với tôi - hình ảnh pixel
Async- Ngày

Đã làm việc cho tôi trong Swift 3. Cảm ơn !!
oscar castellon

4
Không bảo toàn tỷ lệ và định hướng.
Shailesh

bên trong mở rộng, chức năng nên được công khai
Shivam Pokhriyal

88

Có một phương thức tích hợp để lấy một phương thức được UIImagetự động hiển thị ở chế độ mẫu . Điều này sử dụng tintColor của một chế độ xem để tạo màu cho hình ảnh:

let templateImage = originalImage.imageWithRenderingMode(UIImageRenderingModeAlwaysTemplate)
myImageView.image = templateImage
myImageView.tintColor = UIColor.orangeColor()

2
Đây là câu trả lời hay nhất - có thể tìm thấy thêm thông tin trong Apple Docs - developer.apple.com/library/content/documentation/…
Đánh dấu

6
Xem Swift 3 cú pháp cho chế độ render ở đây: stackoverflow.com/a/24145287/448718
Phil_Ken_Sebben

6
sử dụng ImageView là hiển nhiên, nhưng chúng tôi muốn UIImage chỉ
djdance

3
không phải là một giải pháp nếu bạn đang làm việc với các đối tượng UIImage độc ​​lập với UIImageView. Điều này chỉ hoạt động nếu bạn có quyền truy cập vào UIImageView
Pez

Hoạt động tuyệt vời ngay cả trong trường hợp khi myImageView là một UIButton
daxh

42

Đầu tiên, bạn phải thay đổi thuộc tính kết xuất của hình ảnh thành "Hình ảnh Mẫu" trong thư mục .xcassets. Sau đó, bạn có thể chỉ cần thay đổi thuộc tính màu sắc của phiên bản UIImageView của bạn như sau:

imageView.tintColor = UIColor.whiteColor()

nhập mô tả hình ảnh ở đây


1
Đã tintColorbị xóa khỏi UIImagemột số thời điểm? Tôi đã vui mừng về câu trả lời này, nhưng nó dường như không tồn tại trong iOS 10
Travis Griggs

1
Xin chào @TravisGriggs. Xin lỗi, tôi đã vừa mới chỉnh sửa câu trả lời của tôi là một chút mô tả nhiều hơn, tài sản tintColor là trên UIImageView, không UIImage
Harry Bloom

Tx, điều này thật tuyệt! Lưu ý: Màu sắc xuất hiện trong phần Chế độ xem của trình kiểm tra ImageView, nằm phía dưới một chút. Chỉ để thêm rõ ràng.
Andy Weinstein

29

Tôi đã kết thúc với điều này vì các câu trả lời khác mất độ phân giải hoặc hoạt động với UIImageView, không phải UIImage hoặc chứa các hành động không cần thiết:

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
Câu trả lời tốt nhất ở đây, giữ cùng một định hướng hình ảnh và chất lượng
SmartTree

Vâng, tôi đã thử nghiệm tất cả các câu trả lời ở trên và điều này thực sự cần xem xét quy mô, vì vậy nó sẽ không cung cấp cho bạn pixelated UIImage. Câu trả lời thực sự tốt đẹp, cảm ơn bạn!
Guilherme Matuella 21/10/18

21

Chức năng này sử dụng đồ họa lõi để đạt được điều này.

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
Điều này hoạt động, trong đó hai câu trả lời hàng đầu khác là sai.
chrysb

4
Có điều này hoạt động hoàn hảo. maskWithColor tiện ích mở rộng hoạt động nhưng điều đó bỏ qua scalevì vậy hình ảnh trông không sắc nét trên các thiết bị có độ phân giải cao hơn.
Moin Uddin

Điều này hoạt động hoàn hảo !! Chúng tôi sử dụng trong một tiện ích mở rộng và chạy OK. Những người khác giải pháp bỏ qua quy mô ...
Javi Campana

17

Đối với swift 4.2 để thay đổi màu sắc hình ảnh UII như bạn muốn (màu đồng nhất)

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

Cách sử dụng

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

10

Tạo tiện ích mở rộng trên 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!
    }
}

Sau đó, bạn có thể sử dụng nó như vậy:

image.maskWithColor(UIColor.redColor())

1
Bỏ qua điều này scale, orientationvà các thông số khác của UIImage.
Nikolai Ruhe

10

Tôi thấy giải pháp của HR là hữu ích nhất nhưng đã điều chỉnh nó một chút cho 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!
    }
}

Điều này có tính đến quy mô cân nhắc và cũng không tạo ra hình ảnh có độ phân giải thấp hơn như một số giải pháp khác. Sử dụng :

image = image.maskWithColor(color: .green )

Đây chắc chắn là cách triển khai để sử dụng (tách biệt khỏi những cái khác trên trang này).
Scott Corscadden

Để an toàn hơn, các hộp buộc phải được bọc trong if-allow hoặc một tấm bảo vệ.
Chris Paveglio

5

Trình bao bọc tiện ích mở rộng Swift 3 từ câu trả lời @Nikolai Ruhe.

extension UIImageView {

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

}

Nó cũng có thể được sử dụng UIButton, ví dụ:

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

Thêm phần mở rộng này vào mã của bạn và thay đổi màu hình ảnh trong chính bảng phân cảnh.

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

Xem trước bảng phân cảnh:

nhập mô tả hình ảnh ở đây



1

Swift 3

21 tháng 6, 2017

Tôi sử dụng CALayer để che hình ảnh đã cho bằng 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

Phiên bản Swift 3 với thang đo và định hướng từ @kuzdu answer

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.

Sử dụng tiện ích mở rộng này để tạo hình ảnh có màu đồng nhất

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

Đã làm việc cho tôi trong navigationBar.setBackgroundImage và Swift 5. Cảm ơn!
Jesse

1

Đăng iOS 13, bạn có thể sử dụng nó như thế này

arrowWhiteImage.withTintColor(.black, renderingMode: .alwaysTemplate)

1

Thêm chức năng mở rộng:

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

Sử dụng như:

anyImageView.setImage(named: "image_name", color: .red)

0

Đây là phiên bản 3 nhanh chóng của giải pháp HR.

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

Vì tôi thấy câu trả lời của Darko rất hữu ích trong việc tô màu các ghim tùy chỉnh cho chú thích mapView, nhưng phải thực hiện một số chuyển đổi cho Swift 3, nên tôi nghĩ rằng tôi sẽ chia sẻ mã cập nhật cùng với đề xuất của mình cho câu trả lời của anh ấy:

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

Tôi đã sửa đổi tiện ích mở rộng được tìm thấy ở đây: Github Gist , Swift 3mà tôi đã thử nghiệm trong bối cảnh tiện ích mở rộng cho 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
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.