Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gaussian blur on full screen

I want to blur the whole screen of my iOS app, and I can't use UIBlurEffect because I want to be able to control the blurriness. So I'm trying to use CIGaussianBlur, but I'm having trouble with the edges of the screen.

I'm taking a screenshot of the screen, and then running it through a CIFilter with CIGaussianBlur, converting the CIImage back to UIImage, and adding the new blurred image on top of the screen.

Here's my code:

    let layer = UIApplication.sharedApplication().keyWindow?.layer
    UIGraphicsBeginImageContext(view.frame.size)

    layer!.renderInContext(UIGraphicsGetCurrentContext()!)
    let screenshot = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    let blurRadius = 5
    var ciimage: CIImage = CIImage(image: screenshot)!
    var filter: CIFilter = CIFilter(name:"CIGaussianBlur")!
    filter.setDefaults()
    filter.setValue(ciimage, forKey: kCIInputImageKey)
    filter.setValue(blurRadius, forKey: kCIInputRadiusKey)

    let ciContext = CIContext(options: nil)
    let result = filter.valueForKey(kCIOutputImageKey) as! CIImage!
    let cgImage = ciContext.createCGImage(result, fromRect: view.frame)

    let finalImage = UIImage(CGImage: cgImage)


    let blurImageView = UIImageView(frame: view.frame)
    blurImageView.image = finalImage
    blurImageView.sizeToFit()
    blurImageView.contentMode = .ScaleAspectFit
    blurImageView.center = view.center
    view.addSubview(blurImageView)

Here is what I see:

Gaussian blur applied to screenshot

It looks almost right except the edges. It seems that the blurrisness is taking off from the blur radius to the edge. I tried playing with the context size but couldn't seem to make it work.

How can I make the blur go all the way to the edges?

like image 775
Wiingaard Avatar asked Jan 23 '16 13:01

Wiingaard


1 Answers

It is happening because the gaussian blur filter samples pixels outside the edges of the image. But because there are no pixels, you get this weird artefact. You can use "CIAffineClamp" filter to "extend" your image infinitely in all directions.

Please see this answer https://stackoverflow.com/a/18138742/762779

I tried running your code with chained 'CIAffineClamp-> CIGaussianBlur' filters and got good results.

let layer = UIApplication.sharedApplication().keyWindow?.layer
UIGraphicsBeginImageContext(view.frame.size)

layer!.renderInContext(UIGraphicsGetCurrentContext()!)
let screenshot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

let blurRadius = 5
let ciimage: CIImage = CIImage(image: screenshot)!

// Added "CIAffineClamp" filter 
let affineClampFilter = CIFilter(name: "CIAffineClamp")!
affineClampFilter.setDefaults()
affineClampFilter.setValue(ciimage, forKey: kCIInputImageKey)
let resultClamp = affineClampFilter.valueForKey(kCIOutputImageKey)

// resultClamp is used as input for "CIGaussianBlur" filter
let filter: CIFilter = CIFilter(name:"CIGaussianBlur")!
filter.setDefaults()
filter.setValue(resultClamp, forKey: kCIInputImageKey)
filter.setValue(blurRadius, forKey: kCIInputRadiusKey)


let ciContext = CIContext(options: nil)
let result = filter.valueForKey(kCIOutputImageKey) as! CIImage!
let cgImage = ciContext.createCGImage(result, fromRect: ciimage.extent) // changed to ciiimage.extend 

let finalImage = UIImage(CGImage: cgImage)

let blurImageView = UIImageView(frame: view.frame)
blurImageView.image = finalImage
blurImageView.sizeToFit()
blurImageView.contentMode = .ScaleAspectFit
blurImageView.center = view.center
view.addSubview(blurImageView)
like image 129
euvs Avatar answered Oct 18 '22 23:10

euvs