2

So, I've got an odd scenario.

In my iOS app, I'm trying to blur the content area of the screen when a popover is opened. I have this working when using Core Image, but only when using Gaussian blur- none of the other blurs work, which is odd.

I tried doing the same with GPUImage, and it blurs far faster, but doesn't actually put the view on top of the other views!

To summarize: in the source below, setBlurOnView will work properly- however setBlurOnViewWithGPUImage appears to not be working. The blur view (tag 6110) is created, but the app doesn't actually blur.

Note: This is on iOS 6, in the simulator.

Here's the relevant source:

//  ScreenBlur.m

#import <QuartzCore/QuartzCore.h>
#import <CoreImage/CoreImage.h>
#import <GPUImage/GPUImage.h>

#import "ScreenBlur.h"
#import "GlobalData.h"
#import "Logger.h"

@implementation ScreenBlur

+ (void) setBlurOnViewWithGPUImage:(UIView*)view {
    GPUImagePicture *imageSource = [[GPUImagePicture alloc] initWithImage:[self captureScreenInRect:view.frame inView:view]];
    GPUImageGaussianBlurFilter *blur = [[GPUImageGaussianBlurFilter alloc] init];

    [imageSource addTarget:blur];
    [imageSource processImage];

    [self setImage:[imageSource imageFromCurrentlyProcessedOutput] toView:view];
}

+ (void) setBlurOnView:(UIView *)view {
    //http://stackoverflow.com/questions/17041669/creating-a-blurring-overlay-view

    CIImage *inputImage = [CIImage imageWithCGImage:[self captureScreenInRect:view.frame inView:view].CGImage];
    //CIContext *context = [CIContext contextWithOptions:nil];
    if ([GlobalData getInstance].ciContext == nil) {
        [Logger Log:@"ciContext does not exist, creating..." fromClass:@"ScreenBlur"];
//        [GlobalData getInstance].ciContext = [CIContext contextWithOptions:nil]; //cpu context
        [GlobalData getInstance].ciContext = [CIContext contextWithEAGLContext:[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]];
    }


    //set up the blur filter
    CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
    [filter setValue:inputImage forKey:kCIInputImageKey];
    [filter setValue:[NSNumber numberWithFloat:3.0f] forKey:@"inputRadius"];
    CIImage *result = [filter valueForKey:kCIOutputImageKey];

    // CIGaussianBlur has a tendency to shrink the image a little,
    // this ensures it matches up exactly to the bounds of our original image
    CGImageRef cgImage = [[GlobalData getInstance].ciContext createCGImage:result fromRect:[inputImage extent]];

    [self setImage:[UIImage imageWithCGImage:cgImage] toView:view];
}

+ (void) setImage:(UIImage*)blurredImage toView:(UIView*)view {
    UIView *blurView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, blurredImage.size.width, blurredImage.size.height)];
    [blurView setBackgroundColor:[UIColor colorWithPatternImage:blurredImage]];
    [blurView setTag:6110];

    //set the image as the foreground for the view
    [view addSubview:blurView];
    [view bringSubviewToFront:blurView];
}

//same as the method above, but resizes the screenshot before applying the blur for increased performance at the expense of image quality.
+ (void) setBlurOnViewPerformanceMode:(UIView *)view {
    //http://stackoverflow.com/questions/17041669/creating-a-blurring-overlay-view

    UIImage *screenShot = [self imageWithImage:[self captureScreenInRect:view.frame inView:view] scaledToSize:CGSizeMake(view.frame.size.width / 2, view.frame.size.height / 2)];
    CIImage *inputImage = [CIImage imageWithCGImage:screenShot.CGImage];
    //CIContext *context = [CIContext contextWithOptions:nil];
    if ([GlobalData getInstance].ciContext == nil) {
        [Logger Log:@"ciContext does not exist, creating..." fromClass:@"ScreenBlur"];
        //        [GlobalData getInstance].ciContext = [CIContext contextWithOptions:nil]; //cpu context
        [GlobalData getInstance].ciContext = [CIContext contextWithEAGLContext:[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]];
    }

    //set up the blur filter
    CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
    [filter setValue:inputImage forKey:kCIInputImageKey];
    [filter setValue:[NSNumber numberWithFloat:3.0f] forKey:@"inputRadius"];
    CIImage *result = [filter valueForKey:kCIOutputImageKey];

    //CGImageRef cgImage = [[GlobalData getInstance].ciContext createCGImage:result fromRect:[inputImage extent]];
    CGImageRef cgImage = [[GlobalData getInstance].ciContext createCGImage:result fromRect:[inputImage extent]];

    [self setImage:[self imageWithImage:[UIImage imageWithCGImage:cgImage] scaledToSize:view.frame.size] toView:view];
}

+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
    //UIGraphicsBeginImageContext(newSize);
    UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
    [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}


+ (void) removeBlurFromView:(UIView *)view {
    for (UIView *subView in view.subviews) {
        if (subView.tag == 6110) {
            [subView removeFromSuperview];
        }
    }
}

+ (UIImage *)captureScreenInRect:(CGRect)captureFrame inView:(UIView*) view {
    CALayer *layer;
    layer = view.layer;
    UIGraphicsBeginImageContext(view.bounds.size);
    CGContextClipToRect (UIGraphicsGetCurrentContext(),captureFrame);
    [layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *screenImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return screenImage;
}

@end

And then in my view controller, it's simply called with

[ScreenBlur setBlurOnView:self.view];
jssblck
  • 529
  • 5
  • 20

1 Answers1

0

I found a workaround for this (or, who knows, maybe this is how it was supposed to be done).

//ScreenBlur.m
+ (GPUImageView*) getBlurredImageWithGPUImageFromView:(UIView*)view {
    GPUImagePicture *imageSource = [[GPUImagePicture alloc] initWithImage:[self captureScreenInRect:view.frame inView:view] smoothlyScaleOutput:true];

    GPUImageFastBlurFilter *blur = [[GPUImageFastBlurFilter alloc] init];
    [blur setBlurPasses:3];

    [imageSource addTarget:blur];

    GPUImageView *filteredView = [[GPUImageView alloc] initWithFrame:view.frame];
    [blur addTarget:filteredView];

    [imageSource processImage];


    return filteredView;
}

//ViewController.m
//blur the main screen
GPUImageView *blurred = [ScreenBlur getBlurredImageWithGPUImageFromView:self.view];
[blurred setTag:6110];
[self.view addSubview:blurred];
[self.view bringSubviewToFront:blurred];
jssblck
  • 529
  • 5
  • 20