如何在 Swift 中为 UIImage 着色?

我有一个图像称为 arrowWhite。我想把这个图像染成黑色。

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
}

I want to get this image in blackColour.
tintColor不起作用..。

137038 次浏览

Create an extension on 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!
}
}

然后你可以这样使用它:

image.maskWithColor(UIColor.redColor())

斯威夫特4号和5号

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

这样打电话:

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

另一个选择 For Swift 3, 4 or 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
}
}


}

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

这样打电话:

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

有一个内置的方法可以获得在 模板模式中自动呈现的 UIImage。这使用视图的 tintColor 为图像着色:

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

这个函数使用核心图形来实现这一点。

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
}

Since I found Darko's answer very helpful in colorizing custom pins for mapView annotations, but had to do some conversions for Swift 3, thought I'd share the updated code along with my recommendation for his answer:

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

首先,您必须将图像的呈现属性更改为. xcassets 文件夹中的“ Template Image”。 然后您可以像下面这样改变 UIImageView 实例的色彩属性:

imageView.tintColor = UIColor.whiteColor()

enter image description here

我发现 H R 的解决方案非常有帮助,但是对 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!
}
}

这考虑到规模,也不像其他一些解决方案一样产生较低的分辨率图像。 用法:

image = image.maskWithColor(color: .green )

来自@Nikolai Ruhe 的 Swift 3扩展包装。

extension UIImageView {


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


}

它也可以用于 UIButton,例如:

button.imageView?.maskWith(color: .blue)

这里是快速人力资源解决方案的3个版本。

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
}

我之所以这样做,是因为其他答案要么失去分辨率,要么使用 UIImageView,而不是 UIImage,要么包含不必要的操作:

Swift 3

extension UIImage {
    

public func mask(with 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
}
    

}

Swift 3

21 June 2017

我使用 CALayer 来掩盖给定的图像与阿尔法通道

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

我已经修改了这里找到的扩展: Github Gist,针对 Swift 3,我已经在 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
}

Swift 3版本,带缩放和方向,来自@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
}
}
}

Swift 4

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

Swift 4.

使用此扩展创建 纯色图像纯色图像

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

对于快速4.2,可以根据需要更改 UIImage 颜色(纯色)

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

How to use

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

在代码中添加这个扩展,并在故事板中更改图像颜色。

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

故事板预览:

enter image description here

Post iOS 13 you can use it something like this

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

添加扩展功能:

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

用法如下:

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

对于 iOS13 + ,有 WithTintColor (_ _:)WithTintColor (_: renderingMode:)两种方法。

示例用法:

let newImage = oldImage.withTintColor(.red)

or

let newImage = oldImage.withTintColor(.red, renderingMode: .alwaysTemplate)

简单的方法:

yourIcon.image = yourIcon.image?.withRenderingMode(.alwaysTemplate)
yourIcon.tintColor = .someColor

顺便说一下,它在 Android 上更有趣!

yourIcon.setColorFilter(getColor(R.color.someColor), PorterDuff.Mode.MULTIPLY);