Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS blend mode multiply

I'm looking for a solution to create this red box:

enter image description here

It is using a color filter 'Multiply'. Currently I have found this information: https://developer.apple.com/library/mac/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_images/dq_images.html

But how can I use something like the multiply effect on a UIView or isn't this possible? So that the background is a UIImageView and the red box is a UIView with the multiply effect.

like image 615
Francesco verheye Avatar asked Apr 09 '15 14:04

Francesco verheye


People also ask

How do you set blend mode to Multiply?

To use it, right-click on a layer, select "Blending Options…" and then set "Blend Mode: Multiply".

What is mix blend mode Multiply?

normal : this attribute applies no blending whatsoever. multiply : the element is multiplied by the background and replaces the background color. The resulting color is always as dark as the background. screen : multiplies the background and the content then complements the result.

What blending mode is the opposite of Multiply?

Multiply darkens shadows more than it darkens highlights. Screen mode LIGHTENS highlights.


2 Answers

This Swift extension did the trick for me.

extension UIImage {

//creates a static image with a color of the requested size
static func fromColor(color: UIColor, size: CGSize) -> UIImage {
    let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
    UIGraphicsBeginImageContext(rect.size)
    let context = UIGraphicsGetCurrentContext()
    CGContextSetFillColorWithColor(context, color.CGColor)
    CGContextFillRect(context, rect)
    let img = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return img
}


func blendWithColorAndRect(blendMode: CGBlendMode, color: UIColor, rect: CGRect) -> UIImage {

    let imageColor = UIImage.fromColor(color, size:self.size)

    let rectImage = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)

    UIGraphicsBeginImageContextWithOptions(self.size, true, 0)
    let context = UIGraphicsGetCurrentContext()

    // fill the background with white so that translucent colors get lighter
    CGContextSetFillColorWithColor(context, UIColor.whiteColor().CGColor)
    CGContextFillRect(context, rectImage)

    self.drawInRect(rectImage, blendMode: .Normal, alpha: 1)
    imageColor.drawInRect(rect, blendMode: blendMode, alpha: 1)

    // grab the finished image and return it
    let result = UIGraphicsGetImageFromCurrentImageContext()

    //self.backgroundImageView.image = result
    UIGraphicsEndImageContext()
    return result

   }
}

Swift 3:

static func fromColor(color: UIColor, size: CGSize) -> UIImage {
  let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
  UIGraphicsBeginImageContext(rect.size)
  let context = UIGraphicsGetCurrentContext()
  context!.setFillColor(color.cgColor)
  context!.fill(rect)
  let img = UIGraphicsGetImageFromCurrentImageContext()
  UIGraphicsEndImageContext()
  return img!
}


func blendWithColorAndRect(blendMode: CGBlendMode, color: UIColor, rect: CGRect) -> UIImage {

  let imageColor = UIImage.fromColor(color: color, size:self.size)

  let rectImage = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)

  UIGraphicsBeginImageContextWithOptions(self.size, true, 0)
  let context = UIGraphicsGetCurrentContext()

  // fill the background with white so that translucent colors get lighter
  context!.setFillColor(UIColor.white.cgColor)
  context!.fill(rectImage)

  self.draw(in: rectImage, blendMode: .normal, alpha: 1)
  imageColor.draw(in: rect, blendMode: blendMode, alpha: 1)

  // grab the finished image and return it
  let result = UIGraphicsGetImageFromCurrentImageContext()

  //self.backgroundImageView.image = result
  UIGraphicsEndImageContext()
  return result!

}

But only works for images, I would like to work for videos too :|

like image 121
Pau Ballada Avatar answered Sep 21 '22 19:09

Pau Ballada


I expanded @pegpeg solution and added a gradient overlay to the image instead of a 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()

    // fill the background with white so that translucent colors get lighter
    context!.setFillColor(UIColor.white.cgColor)
    context!.fill(rectImage)

    self.draw(in: rectImage, blendMode: .normal, alpha: 1)
    imageColor.draw(in: rect, blendMode: blendMode, alpha: alpha)

    // grab the finished image and return it
    let result = UIGraphicsGetImageFromCurrentImageContext()

    //self.backgroundImageView.image = result
    UIGraphicsEndImageContext()
    return result!

}

the colors array should be of the same length of the locations array, example:

let  newImage = image.blendWithGradientAndRect(blendMode: .multiply,
                                               colors: [.red, .white],
                                               locations: [0,1],
                                               horizontal: true,
                                               alpha: 0.8,
                                               rect: imageRect)
like image 29
Benjamin Jimenez Avatar answered Sep 21 '22 19:09

Benjamin Jimenez