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.
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:
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")
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...