Lenny1357
Lenny1357

Reputation: 778

Apply CIFilters on UI elements

I want to apply an CIFilter on an UI element. I tried to apply it onto the views layer via the .filters member. However the filter won`t get applied.

Upvotes: 0

Views: 917

Answers (1)

Flex Monkey
Flex Monkey

Reputation: 3633

Here's an approach: use UIGraphicsGetImageFromCurrentImageContext to generate a UIImage, apply the filter to that and overlay an image view containing the filtered image over your original component.

Here's a way to do that with a blur (taken from my blog):

Getting a blurred representation of a UIView is pretty simple: I need to begin an image context, use the view's layer's renderInContext method to render into the context and then get a UIImage from the context:

UIGraphicsBeginImageContextWithOptions(CGSize(width: frame.width, height: frame.height), false, 1)

layer.renderInContext(UIGraphicsGetCurrentContext()!)

let image = UIGraphicsGetImageFromCurrentImageContext()


UIGraphicsEndImageContext();

Once I have the image populated, it's a fairly standard workflow to apply a Gaussian blur to it:

guard let blur = CIFilter(name: "CIGaussianBlur") else
{
    return
}

blur.setValue(CIImage(image: image), forKey: kCIInputImageKey)
blur.setValue(blurRadius, forKey: kCIInputRadiusKey)

let ciContext  = CIContext(options: nil)

let result = blur.valueForKey(kCIOutputImageKey) as! CIImage!

let boundingRect = CGRect(x: -blurRadius * 4,
    y: -blurRadius * 4,
    width: frame.width + (blurRadius * 8),
    height: frame.height + (blurRadius * 8))

let cgImage = ciContext.createCGImage(result, fromRect: boundingRect)


let filteredImage = UIImage(CGImage: cgImage)

A blurred image will be larger than its input image, so I need to be explicit about the size I require in createCGImage.

The next step is to add a UIImageView to my view and hide all the other views. I've subclassed UIImageView to BlurOverlay so that when it comes to removing it, I can be sure I'm not removing an existing UIImageView:

let blurOverlay = BlurOverlay()
blurOverlay.frame = boundingRect

blurOverlay.image = filteredImage

subviews.forEach{ $0.hidden = true }


addSubview(blurOverlay)

When it comes to de-blurring, I want to ensure the last subview is one of my BlurOverlay remove it and unhide the existing views:

func unBlur()
{
    if let blurOverlay = subviews.last as? BlurOverlay
    {
        blurOverlay.removeFromSuperview()

        subviews.forEach{ $0.hidden = false }
    }

}

Finally, to see if a UIView is currently blurred, I just need to see if its last subview is a BlurOverlay:

var isBlurred: Bool
{
    return subviews.last is BlurOverlay
}

Upvotes: 1

Related Questions