I expanded @pegpeg solution and added gradient overlay on image instead of single color
Swift 4:
static func fromGradient(colors: [UIColor], locations: [CGFloat], horizontal: Bool, size: CGSize) -> UIImage { let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height) UIGraphicsBeginImageContext(rect.size) let context = UIGraphicsGetCurrentContext() let colorSpace = CGColorSpaceCreateDeviceRGB() let cgColors = colors.map {$0.cgColor} as CFArray let grad = CGGradient(colorsSpace: colorSpace, colors: cgColors , locations: locations) let startPoint = CGPoint(x: 0, y: 0) let endPoint = horizontal ? CGPoint(x: size.width, y: 0) : CGPoint(x: 0, y: size.height) context?.drawLinearGradient(grad!, start: startPoint, end: endPoint, options: .drawsAfterEndLocation) let img = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return img! } func blendWithGradientAndRect(blendMode: CGBlendMode, colors: [UIColor], locations: [CGFloat], horizontal: Bool = false, alpha: CGFloat = 1.0, rect: CGRect) -> UIImage { let imageColor = UIImage.fromGradient(colors: colors, locations: locations, horizontal: horizontal, size: size) let rectImage = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height) UIGraphicsBeginImageContextWithOptions(self.size, true, 0) let context = UIGraphicsGetCurrentContext()
an array of colors should have the same length of an array of locations, for example:
let newImage = image.blendWithGradientAndRect(blendMode: .multiply, colors: [.red, .white], locations: [0,1], horizontal: true, alpha: 0.8, rect: imageRect)