How to add a blur mask with a custom shape above a dynamic camera view in Swift?

后端 未结 2 688
孤城傲影
孤城傲影 2021-02-06 13:32

I am using Swift to develop an iOS application with a camera feature, and it requires a blur layer above the camera view with a hole in the middle like the image shown below.

相关标签:
2条回答
  • 2021-02-06 13:54

    I've done this by creating an overlay with a layer with said blurred image, and then using a mask that is built from a path that goes all the way around the extents, and then jumps to the cutout hole, going the opposite direction with the winding fill rule.

    Refer to documetation here:

    https://developer.apple.com/library/ios/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_paths/dq_paths.html

    There are many documented examples of this though, here is one: drawing with clear color on UIView (cutting a hole) in static method

    0 讨论(0)
  • 2021-02-06 14:11

    This question asked a long time a go but I cannot see any useful answer that's why I'll answer it maybe it help others.

    Easiest way to apply blur to out of some circular region in image we can applying Gaussian blur and gradient masks. Here Apple has a post on it.

    Basically common steps to do this:

    1. Create a mask filter using CIRadialGradient (adjust your circle center here)

      guard let radialMask = CIFilter(name:"CIRadialGradient") else {
         return nil
      }
      
      let h = inputImage.extent.size.height
      let w = inputImage.extent.size.width
      
      // Adjust your circular hole position here
      let imageCenter = CIVector(x:0.55 * w, y:0.6 * h)
      radialMask.setValue(imageCenter, forKey:kCIInputCenterKey)
      // Small fraction of the image's dimension (high sharp)
      radialMask.setValue(0.2 * h, forKey:"inputRadius0")
      // Large fraction of the image's dimension (lower sharp)
      radialMask.setValue(0.3 * h, forKey:"inputRadius1")
      radialMask.setValue(CIColor(red:0, green:1, blue:0, alpha:0), 
                          forKey:"inputColor0")
      radialMask.setValue(CIColor(red:0, green:1, blue:0, alpha:1), 
                          forKey:"inputColor1")
      
    2. Create CIMaskedVariableBlur to mask blured area

      guard let maskedVariableBlur = CIFilter(name:"CIMaskedVariableBlur") else {
         return nil
      }
      // inputImage:- Your original image
      maskedVariableBlur.setValue(inputImage, forKey: kCIInputImageKey)
      // inputRadiusKey:- Right degree of blur desired
      maskedVariableBlur.setValue(10, forKey: kCIInputRadiusKey)
      // here we will use result of radialMask filter result image
      maskedVariableBlur.setValue(radialMask.outputImage, forKey: "inputMask")
      // Get result image
      let selectivelyFocusedCIImage = maskedVariableBlur.outputImage
      // Convert your result image to UIImage
      let resultImage = UIImage(ciImage: selectivelyFocusedCIImage)
      

    Extra:- You can use UIPanGestureRecognizer to move your circle hole

    1- Create gesture recognizer:

    lazy var panGesture: UIPanGestureRecognizer = {
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handleDrag))
        return panGesture
    }()
    

    2- Add gesture recognizer to your image view

    self.imageView.isUserInteractionEnabled = true
    self.imageView.addGestureRecognizer(panGesture)
    

    3- Handle your gesture

    var initialCenter = CGPoint()
    @objc fileprivate func handleDrag(_ gestureRecognizer: UIPanGestureRecognizer) {
      guard gestureRecognizer.view != nil else {return}
    
      let translation = gestureRecognizer.translation(in: imageView.superview)
    
      if gestureRecognizer.state == .began {
          // Save the view's original position.
          self.initialCenter = CGPoint(x: centerVector.x, y: centerVector.y)
      }
      // Update the position for the .began, .changed, and .ended states
      if gestureRecognizer.state != .cancelled {
          // Add the X and Y translation to the view's original position.
          let newCenter = CGPoint(x: initialCenter.x + translation.x, y: initialCenter.y + -translation.y)
    
    
          self.imageCenter = CIVector.init(cgPoint: newCenter)
          // Then apply your filter on gestureRecognizer.state == .end
    
      } else {
          // On cancellation, return the piece to its original location.
          self.imageCenter = CIVector(x: initialCenter.x, y: initialCenter.y)
      }
    }
    

    Happy coding...

    0 讨论(0)
提交回复
热议问题