Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Blur screen with iOS 7's snapshot API

I believe the NDA is down, so I can ask this question. I have a UIView subclass:

BlurView *blurredView = ((BlurView *)[self.view snapshotViewAfterScreenUpdates:NO]);
blurredView.frame = self.view.frame;
[self.view addSubview:blurredView];

It does its job so far in capturing the screen, but now I want to blur that view. How exactly do I go about this? From what I've read I need to capture the current contents of the view (context?!) and convert it to CIImage (no?) and then apply a CIGaussianBlur to it and draw it back on the view.

How exactly do I do that?

P.S. The view is not animated, so it should be OK performance wise.

EDIT: Here is what I have so far. The problem is that I can't capture the snapshot to a UIImage, I get a black screen. But if I add the view as a subview directly, I can see the snapshot is there.

// Snapshot
UIView *view = [self.view snapshotViewAfterScreenUpdates:NO];

// Convert to UIImage
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

// Apply the UIImage to a UIImageView
BlurView *blurredView = [[BlurView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
[self.view addSubview:blurredView];
blurredView.imageView.image = img;

// Black screen -.-

BlurView.m:

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];

    if (self) {
        // Initialization code
        self.imageView = [[UIImageView alloc] init];
        self.imageView.frame = CGRectMake(20, 20, 200, 200);
        [self addSubview:self.imageView];
    }
    return self;
}
like image 669
Nikolay Dyankov Avatar asked Nov 27 '22 21:11

Nikolay Dyankov


1 Answers

Half of this question didn't get answered, so I thought it worth adding.

The problem with UIScreen's

- (UIView *)snapshotViewAfterScreenUpdates:(BOOL)afterUpdates

and UIView's

- (UIView *)resizableSnapshotViewFromRect:(CGRect)rect 
                      afterScreenUpdates:(BOOL)afterUpdates 
                           withCapInsets:(UIEdgeInsets)capInsets

Is that you can't derive a UIImage from them - the 'black screen' problem.

In iOS7 Apple provides a third piece of API for extracting UIImages, a method on UIView

- (BOOL)drawViewHierarchyInRect:(CGRect)rect 
             afterScreenUpdates:(BOOL)afterUpdates  

It is not as fast as snapshotView, but not bad compared to renderInContext (in the example provided by Apple it is five times faster than renderInContext and three times slower than snapshotView)

Example use:

 UIGraphicsBeginImageContextWithOptions(image.size, NULL, 0);
 [view drawViewHierarchyInRect:rect];
 UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
 UIGraphicsEndImageContext();  

Then to get a blurred version

 UIImage* lightImage = [newImage applyLightEffect];  

where applyLightEffect is one of those Blur category methods on Apple's UIImage+ImageEffects category mentioned in the accepted answer (the enticing link to this code sample in the accepted answer doesn't work, but this one will get you to the right page: the file you want is iOS_UIImageEffects).

The main reference is to WWDC2013 session 226, Implementing Engaging UI on iOS

By the way, there is an intriguing note in Apple's reference docs for renderInContext that hints at the black screen problem..

Important: The OS X v10.5 implementation of this method does not support the entire Core Animation composition model. QCCompositionLayer, CAOpenGLLayer, and QTMovieLayer layers are not rendered. Additionally, layers that use 3D transforms are not rendered, nor are layers that specify backgroundFilters, filters, compositingFilter, or a mask values. Future versions of OS X may add support for rendering these layers and properties.

The note hasn't been updated since 10.5, so I guess 'future versions' may still be a while off, and we can add our new CASnapshotLayer (or whatever) to the list.

like image 102
foundry Avatar answered Dec 16 '22 01:12

foundry