A more efficient method of blurring a small section of a UIView?

392 views Asked by At

I am wanting to capture a snapshot of a small area of the screen and apply a blur to it - albeit at 60fps - which is not possible with this code:

let rectangle = CGRect(x: -37, y: -153, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)

captureSnapShotWithGaussianBlur(rect: rectangle)

public func captureSnapShotWithGaussianBlur(rect: CGRect) -> UIImage {

      let SCREEN_SIZE_SCALE_FACTOR = UIScreen.main.scale
      let CROPPING_RECT = CGRect(x: 0, y: 0, width: 118*SCREEN_SIZE_SCALE_FACTOR, height: 66*SCREEN_SIZE_SCALE_FACTOR)

      UIGraphicsBeginImageContextWithOptions(CGSize(width: 118, height: 66), true, 0.0)

      backgroundView!.drawHierarchy(in: rect, afterScreenUpdates: true)

      let capturedImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
      let ciimage: CIImage = CIImage(image: capturedImage)!

      UIGraphicsEndImageContext()

      let gaussianfilter: CIFilter = CIFilter(name:"CIGaussianBlur")!
      gaussianfilter.setDefaults()
      gaussianfilter.setValue(ciimage, forKey: kCIInputImageKey)
      gaussianfilter.setValue(10, forKey: kCIInputRadiusKey)

      let outputImage: CIImage = gaussianfilter.outputImage!
      let finalImage: UIImage = UIImage(ciImage: outputImage.cropping(to: CROPPING_RECT), scale: SCREEN_SIZE_SCALE_FACTOR, orientation: UIImageOrientation.up)

      return finalImage

}

One of the problems I see with my code is that I think the Gaussian Blur is applied to the whole image (because of UIScreen.main.bounds used for the drawHierarchy rectangle).

I was hoping there was a way of doing a resizableSnapshotView() of the screen, then doing drawHierarchy in that view and extracting the image - alas, this does not work (although it seems to in the Simulator, but not on the phone where it simply renders black).

Any suggestions on how to make a more performant capture and blur method?

Cheers!

1

There are 1 answers

1
Sean Lintern On

Try using this extension to snapshot the view and blur this, it seems to work on both simulator and device:

extenstion UIView {
    /// A more efficient way to snapshot a UIView other than UIView.snapshot
///
/// - Returns: UIImage representing the snapshot of the UIView
public func snapshotImage() -> UIImage? {
    UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0)
    drawHierarchy(in: bounds, afterScreenUpdates: false)
    let snapshotImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return snapshotImage
}

public func snapshotView() -> UIView? {
    if let snapshotImage = snapshotImage() {
        return UIImageView(image: snapshotImage)
    } else {
        return nil
    }
}
}