merge two different images in Swift - ios

I want to merge two UIImage in Swift:
and
I tried it with
func maskImage(image: UIImage, withMask maskImage: UIImage) -> UIImage {
let maskRef = maskImage.CGImage
let mask = CGImageMaskCreate(
CGImageGetWidth(maskRef),
CGImageGetHeight(maskRef),
CGImageGetBitsPerComponent(maskRef),
CGImageGetBitsPerPixel(maskRef),
CGImageGetBytesPerRow(maskRef),
CGImageGetDataProvider(maskRef),
nil,
false)
let masked = CGImageCreateWithMask(image.CGImage, mask)
let maskedImage = UIImage(CGImage: masked!)
// No need to release. Core Foundation objects are automatically memory managed.
return maskedImage
}
and the call
let imageName = data.valueForKey("imagename")!.description
let image = UIImage(named: imageName)
let imageBackground : UIImage = UIImage(named:"background")!
let maskedImage: UIImage = self.maskImage(image!, withMask: imageBackground)
cell.imageButton.setImage(maskedImage, forState: .Normal)
the result is just the image that i get with let image = UIImage(named: imageName), the second image (volleyball)
What´s my error?

If you don't care about performance you can use Core Image
let volleyballImage = CIImage(image: UIImage(named:"volleyball.png")!)
let otherImage = CIImage(image: UIImage(named:"other.png")!)
let compositeFilter = CIFilter(name: "CIAdditionCompositing")!
compositeFilter.setValue(volleyballImage,
forKey: kCIInputImageKey)
compositeFilter.setValue(otherImage,
forKey: kCIInputBackgroundImageKey)
if let compositeImage = compositeFilter.outputImage{
let image = UIImage(CIImage: compositeImage)
// do something with the "merged" image
}

You can do it in few lines:
var bottomImage:UIImage = UIImage(named: "imageName")!
var topImage:UIImage = UIImage(named:"background")!
// Change here the new image size if you want
var newSize = CGSizeMake(bottomImage.size.width, bottomImage.size.height)
UIGraphicsBeginImageContextWithOptions(newSize, false, bottomImage.scale)
bottomImage.drawInRect(CGRectMake(0,0,newSize.width,newSize.height))
topImage.drawInRect(CGRectMake(0,0,newSize.width,newSize.height), blendMode:CGBlendMode.Normal, alpha:1.0)
var newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

You can use my simple method to merge two images in half.
Like this:
func mergeTwoImage(leftImg:UIImage,rightImg:UIImage) -> UIImage?{
let size = CGSize(width: leftImg.size.width, height: leftImg.size.height)
UIGraphicsBeginImageContext(size)
let area1 = CGRect(x: 0, y: 0, width: size.width, height: size.height)
let area2 = CGRect(x: size.width/2, y: 0, width: size.width, height: size.height)
leftImg.draw(in: area1)
rightImg.draw(in: area2, blendMode: .normal, alpha: 1)
let finalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return finalImage
}

Related

How to make image to watermarkimage in swift [duplicate]

I know there are several other ways to do this; I don't want to import anything that I don't need to. If someone can help me with his code, that would be great.
Currently, it is only saving the original image without the watermark image.
extension UIImage {
class func imageWithWatermark(image1: UIImageView, image2: UIImageView) -> UIImage {
UIGraphicsBeginImageContextWithOptions(image1.bounds.size, false, 0.0)
image2.layer.renderInContext(UIGraphicsGetCurrentContext()!)
image1.layer.renderInContext(UIGraphicsGetCurrentContext()!)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img
}
}
func addWatermark() {
let newImage = UIImage.imageWithWatermark(imageView, image2: watermarkImageView)
UIImageWriteToSavedPhotosAlbum(newImage, nil, nil, nil)
}
EDIT: I've got the watermark appearing on the saved images.
I had to switch the order of the layers:
image1.layer.renderInContext(UIGraphicsGetCurrentContext()!)
image2.layer.renderInContext(UIGraphicsGetCurrentContext()!)
HOWEVER, it is not appearing in the correct place.It seems to always appear in the center of the image.
If you grab the UIImageViews' images you could use the following concept:
if let img = UIImage(named: "image.png"), img2 = UIImage(named: "watermark.png") {
let rect = CGRect(x: 0, y: 0, width: img.size.width, height: img.size.height)
UIGraphicsBeginImageContextWithOptions(img.size, true, 0)
let context = UIGraphicsGetCurrentContext()
CGContextSetFillColorWithColor(context, UIColor.whiteColor().CGColor)
CGContextFillRect(context, rect)
img.drawInRect(rect, blendMode: .Normal, alpha: 1)
img2.drawInRect(CGRectMake(x,y,width,height), blendMode: .Normal, alpha: 1)
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
UIImageWriteToSavedPhotosAlbum(result, nil, nil, nil)
}
SWIFT 4
Use this
let backgroundImage = imageData!
let watermarkImage = #imageLiteral(resourceName: "jodi_url_icon")
let size = backgroundImage.size
let scale = backgroundImage.scale
UIGraphicsBeginImageContextWithOptions(size, false, scale)
backgroundImage.draw(in: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
watermarkImage.draw(in: CGRect(x: 10, y: 10, width: size.width, height: size.height - 40))
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
Use result to UIImageView, tested.

How can I get spesific tableviewcell screenshot with navigationbar?

I'm trying to get screenshot of uitableviewcell and I can succesfully do it. But I cannot append the navigationbar top of the UIImage.
This is what i have:
https://i.imgur.com/8ULUFg5.jpg
This is what i want to get:
https://i.imgur.com/w0IpoYA.png
How can i append navigation bar to image?
I've tried to create new UIImage for create merged image but it doesn't work.
At the below there is my code for get cell's screenshot properly.
let cell = self.entryView.cellForRow(at: self.indexP) as! entryViewTableCell
let frame = cell.frame
let kalan = self.indexP.row % 2
cell.entryText.backgroundColor = (kalan == 0) ? Theme.cellFirstColor : Theme.cellSecondColor
cell.entryText.text = ""
UIGraphicsBeginImageContextWithOptions(cell.entryText.frame.size, true, 2)
cell.entryText.attributedText = self.entryler[self.indexP.row]
cell.entryText.textColor = Theme.labelColor
cell.entryText.tintColor = Theme.linkColor
cell.entryText.layer.render(in: UIGraphicsGetCurrentContext()!)
let snapshot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
edit:
https://i.imgur.com/OR4gV6L.jpg
I can get this image with below code, but navigationbar opacity too low. How can I opaque it?
let cell = self.entryView.cellForRow(at: self.indexP) as! entryViewTableCell
let frame = cell.entryText.frame
let kalan = self.indexP.row % 2
cell.entryText.backgroundColor = (kalan == 0) ? Theme.cellFirstColor : Theme.cellSecondColor
cell.entryText.text = ""
UIGraphicsBeginImageContextWithOptions(frame.size, true, 2)
cell.entryText.attributedText = self.entryler[self.indexP.row]
cell.entryText.textColor = Theme.labelColor
cell.entryText.tintColor = Theme.linkColor
cell.entryText.layer.render(in: UIGraphicsGetCurrentContext()!)
let snapshot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
UIGraphicsBeginImageContextWithOptions((self.navigationController?.navigationBar.layer.frame.size)!, true, 2)
self.navigationController?.navigationBar.drawHierarchy(in: (self.navigationController?.navigationBar.bounds)!, afterScreenUpdates: false)
self.navigationController?.navigationBar.layer.render(in: UIGraphicsGetCurrentContext()!)
let ss = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
let img = self.getMixedImg(image1: ss!, image2: snapshot!)
func getMixedImg(image1: UIImage, image2: UIImage) -> UIImage? {
let size = CGSize(width: image1.size.width, height: image1.size.height + image2.size.height)
UIGraphicsBeginImageContextWithOptions(size, true, 2)
image1.draw(in: CGRect(x: 0,y: 0,width: size.width, height: image1.size.height))
image2.draw(in: CGRect(x: 0,y: image1.size.height,width: size.width, height: image2.size.height))
let finalImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return finalImage
}
This is answer for my question:
let cell = self.entryView.cellForRow(at: self.indexP) as! entryViewTableCell
let frame = cell.entryText.frame
let kalan = self.indexP.row % 2
cell.entryText.backgroundColor = (kalan == 0) ? Theme.cellFirstColor : Theme.cellSecondColor
cell.entryText.text = ""
UIGraphicsBeginImageContextWithOptions(frame.size, true, 3)
cell.entryText.attributedText = self.entryler[self.indexP.row]
cell.entryText.textColor = Theme.labelColor
cell.entryText.tintColor = Theme.linkColor
cell.entryText.layer.render(in: UIGraphicsGetCurrentContext()!)
let snapshot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
UIGraphicsBeginImageContextWithOptions((self.navigationController?.navigationBar.layer.bounds.size)!, true, 3)
self.navigationController?.navigationBar.drawHierarchy(in: (self.navigationController?.navigationBar.layer.bounds)!, afterScreenUpdates: false)
let ss = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
let img = self.getMixedImg(image1: ss!, image2: snapshot!)
func getMixedImg(image1: UIImage, image2: UIImage) -> UIImage? {
let size = CGSize(width: image1.size.width, height: image1.size.height + image2.size.height)
UIGraphicsBeginImageContextWithOptions(size, true, 2)
image1.draw(in: CGRect(x: 0,y: 0,width: size.width, height: image1.size.height))
image2.draw(in: CGRect(x: 0,y: image1.size.height,width: size.width, height: image2.size.height))
let finalImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return finalImage
}
and result: https://i.imgur.com/ezcfxnw.jpg

Crop Image with CGImageRef

I'm drawing image with core graphics than i want to use it like a mask for another image, but just getting clear rectangular image.
take a look whats wrong with my cropping function ?
UIGraphicsBeginImageContext(CGSizeMake(self.bounds.size.width / 0.5, self.bounds.size.height / 0.5))
let imageCtx = UIGraphicsGetCurrentContext()
CGContextAddArc(imageCtx, CGFloat(self.frame.size.width ) , CGFloat(self.frame.size.height ), 158, 0, CGFloat(DegreesToRadians(Double(angle))) , 0)
CGContextSetLineWidth(imageCtx, 80)
CGContextDrawPath(imageCtx, .Stroke)
let myMask :CGImageRef = CGBitmapContextCreateImage(UIGraphicsGetCurrentContext())!
UIGraphicsEndImageContext()
let maskImage = UIImage(CGImage: myMask)
let testVideoPreview = UIImage(named: "alex")
guard let makedImage = testVideoPreview else {return}
var imageMaskOne: CGImageRef = CGImageMaskCreate(CGImageGetWidth(myMask), CGImageGetHeight(myMask), CGImageGetBitsPerComponent(myMask), CGImageGetBitsPerPixel(myMask), CGImageGetBytesPerRow(myMask), CGImageGetDataProvider(myMask), nil, // Decode is null
true)!
let masked: CGImageRef = CGImageCreateWithMask(makedImage.CGImage, imageMaskOne)!
//Finished
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 350, height: 350))
imageView.image = UIImage(CGImage: masked)
self.addSubview(imageView)
If you just need to create a crop at a specific coordinates there is an easier way CGImageCreateWithImageInRect
func CGImageCreateWithImageInRect(_ image: CGImage?, _ rect: CGRect) -> CGImage?
Here the documentation.

How can I color a UIImage in Swift?

I have an image called arrowWhite. I want to colour this image to black.
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 is not working...
Swift 4 and 5
extension UIImageView {
func setImageColor(color: UIColor) {
let templateImage = self.image?.withRenderingMode(.alwaysTemplate)
self.image = templateImage
self.tintColor = color
}
}
Call like this:
let imageView = UIImageView(image: UIImage(named: "your_image_name"))
imageView.setImageColor(color: UIColor.purple)
Alternativ
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
}
}
}
For 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
}
}
}
Call like this:
let image = UIImage(named: "your_image_name")
testImage.image = image?.maskWithColor(color: UIColor.blue)
There's a built in method to obtain a UIImage that is automatically rendered in template mode. This uses a view's tintColor to color the image:
let templateImage = originalImage.imageWithRenderingMode(UIImageRenderingModeAlwaysTemplate)
myImageView.image = templateImage
myImageView.tintColor = UIColor.orangeColor()
First you have to change the rendering property of the image to "Template Image" in the .xcassets folder.
You can then just change the tint color property of the instance of your UIImageView like so:
imageView.tintColor = UIColor.whiteColor()
I ended up with this because other answers either lose resolution or work with UIImageView, not UIImage, or contain unnecessary actions:
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
}
}
This function uses core graphics to achieve this.
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
}
For swift 4.2 to change UIImage color as you want (solid color)
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)
I found the solution by H R to be most helpful but adapted it slightly for 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!
}
}
This takes into consideration scale and also does not produce a lower res image like some other solutions.
Usage :
image = image.maskWithColor(color: .green )
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!
}
}
Then you can use it like that:
image.maskWithColor(UIColor.redColor())
For iOS13+ there are withTintColor(__:) and withTintColor(_:renderingMode:) methods.
Example usage:
let newImage = oldImage.withTintColor(.red)
or
let newImage = oldImage.withTintColor(.red, renderingMode: .alwaysTemplate)
Swift 3 extension wrapper from #Nikolai Ruhe answer.
extension UIImageView {
func maskWith(color: UIColor) {
guard let tempImage = image?.withRenderingMode(.alwaysTemplate) else { return }
image = tempImage
tintColor = color
}
}
It can be use for UIButton as well, e.g:
button.imageView?.maskWith(color: .blue)
Add this extension in your code and change image color in storyboard itself.
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 Preview:
Swift 4
let image: UIImage? = #imageLiteral(resourceName: "logo-1").withRenderingMode(.alwaysTemplate)
topLogo.image = image
topLogo.tintColor = UIColor.white
Simpleminded way:
yourIcon.image = yourIcon.image?.withRenderingMode(.alwaysTemplate)
yourIcon.tintColor = .someColor
BTW it's more fun on Android!
yourIcon.setColorFilter(getColor(R.color.someColor), PorterDuff.Mode.MULTIPLY);
Add extension Function:
extension UIImageView {
func setImage(named: String, color: UIColor) {
self.image = #imageLiteral(resourceName: named).withRenderingMode(.alwaysTemplate)
self.tintColor = color
}
}
Use like:
anyImageView.setImage(named: "image_name", color: .red)
Post iOS 13 you can use it something like this
arrowWhiteImage.withTintColor(.black, renderingMode: .alwaysTemplate)
Swift 3
21 June 2017
I use CALayer to mask the given image with 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
}
}
Swift 3 version with scale and Orientation from #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
}
}
}
Swift 4.
Use this extension to create a solid colored image
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
}
}
Here is swift 3 version of H R's solution.
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!
}
}
I have modified the extension found here: Github Gist, for Swift 3 which I have tested in the context of an extension for 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
}

UIImage animationImages tint color?

Is there a way to tint the images in an animation?
I know I can tint a single image like this:
var imageOne:UIImage = UIImage(named: "pullto_1.png")!;
imageOne = imageOne.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate);
refSequence.image = imageOne;
But when I try to do it like this it just dosen't work:
var imageOne:UIImage = UIImage(named: "pullto_1.png")!;
imageOne = imageOne.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
var image2:UIImage = UIImage(named: "pullto_2.png")!;
image2 = image2.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
var image3:UIImage = UIImage(named: "pullto_3.png")!;
image3 = image3.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
var image4:UIImage = UIImage(named: "pullto_4.png")!;
image4 = image4.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
refSequence.animationImages = NSArray(objects: imageOne,
image2,
image3,
image4
);
refSequence.animationDuration = 1.4;
refSequence.animationRepeatCount = 99;
refSequence.startAnimating();
Am I doing something wrong? Is there some way to tint the images in the animation?
Thanks
Ok, i hoped that there is a simpler solution but this is what I ended up doing:
This function will create a new image with the wanted color:
func imageWithColor(img:UIImage, color:UIColor)->UIImage{
UIGraphicsBeginImageContextWithOptions(img.size, false, img.scale);
var context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, img.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetBlendMode(context, kCGBlendModeNormal);
var rect = CGRectMake(0, 0, img.size.width, img.size.height);
CGContextClipToMask(context, rect, img.CGImage)
color.setFill();
CGContextFillRect(context, rect);
var newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
And then you can call it like this:
var imageOne:UIImage = UIImage(named: "pullto_1.png")!;
imageOne = imageWithColor(imageOne, color: UIColor.redColor());
var image2:UIImage = UIImage(named: "pullto_2.png")!;
image2 = imageWithColor(image2, color: UIColor.redColor());
var image3:UIImage = UIImage(named: "pullto_3.png")!;
image3 = imageWithColor(image3, color: UIColor.redColor());
var image4:UIImage = UIImage(named: "pullto_4.png")!;
image4 = imageWithColor(image4, color: UIColor.redColor());
loaderS.animationImages = NSArray(objects: imageOne,
image2,
image3,
image4
);
loaderS.animationDuration = 1.4;
loaderS.animationRepeatCount = 99;
loaderS.startAnimating();
Here is a handy UIImage extension:
import UIKit
extension UIImage {
func imageWithTint(tint: UIColor) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, scale)
let context = UIGraphicsGetCurrentContext()
CGContextTranslateCTM(context, 0, size.height)
CGContextScaleCTM(context, 1.0, -1.0)
CGContextSetBlendMode(context, .Normal)
let rect = CGRect(origin: .zero, size: size)
CGContextClipToMask(context, rect, CGImage)
tint.setFill()
CGContextFillRect(context, rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image;
}
}
There's a rdar about this issue (http://www.openradar.me/23517334) and the problem still persists on iOS 11.
I adapted the code examples above to Swift 4.
extension UIImage {
func image(withTintColor color: UIColor) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, scale)
let context = UIGraphicsGetCurrentContext()
context?.translateBy(x: 0, y: size.height)
context?.scaleBy(x: 1.0, y: -1.0)
context?.setBlendMode(.normal)
let rect = CGRect(origin: .zero, size: size)
context?.clip(to: rect, mask: cgImage!)
color.setFill()
context?.fill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}
For Swift 5: Create image with color you want with below function. Then use those images to set to your image view's animation property:
extension UIImage {
func imageWithColor(_ color: UIColor) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale);
guard let context = UIGraphicsGetCurrentContext(), let cgImage = self.cgImage else { return nil }
context.translateBy(x: 0, y: self.size.height)
context.scaleBy(x: 1.0, y: -1.0);
context.setBlendMode(.normal)
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
context.clip(to: rect, mask: cgImage)
color.setFill()
context.fill(rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext();
return newImage
}
}
let animImages = [
image0.imageWithColor(color),
image1.imageWithColor(color),
image2.imageWithColor(color),
].compactMap({ $0 })
imageView.animationImages = animImages
imageView.animationDuration = 0.7
imageView.animationRepeatCount = 0
Here's updated code for Swift 4 with a few safety checks.
extension UIImage {
func image(withTint tint: UIColor) -> UIImage? {
guard let cgImage = cgImage else {
return nil
}
UIGraphicsBeginImageContextWithOptions(size, false, scale)
guard let context = UIGraphicsGetCurrentContext() else {
return nil
}
let rect = CGRect(origin: .zero, size: size)
context.translateBy(x: 0, y: size.height)
context.scaleBy(x: 1.0, y: -1.0)
context.setBlendMode(.normal)
context.clip(to: rect, mask: cgImage)
tint.setFill()
context.fill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
}
Maybe this example extension helps:
extension UIImageView {
func pulsingTintColor() {
UIView.animate(withDuration: 2, delay: 0.0, options: [.repeat, .autoreverse], animations: {
self.tintColor = UIColor.red
self.tintColor = UIColor.green
self.tintColor = UIColor.blue
}, completion: nil)
}
}
Ensure you have set the Render as: Template Image option in your asset catalog. This works for UIViews as well. Just replace tintColor with backgroundColor.
If you need parametrised colours:
func pulsingTintColor(with colors: [UIColor] = [UIColor.red, UIColor.green, UIColor.blue]) {
UIView.animate(withDuration: 2, delay: 0.0, options: [.repeat, .autoreverse], animations: {
colors.forEach({self.tintColor = $0})
}, completion: nil)
}

Resources