Skip to content

Instantly share code, notes, and snippets.

@coolio107
Last active August 29, 2015 13:58
Show Gist options
  • Save coolio107/10164592 to your computer and use it in GitHub Desktop.
Save coolio107/10164592 to your computer and use it in GitHub Desktop.
CoreImage snippet for UIImage blurring
//
// CoreImage filter chain to blur an arbitrary UIImage
// Input: blur radius and target size
// This is assumed to be called on a background queue, it takes a response block to process the completed, blurred image
// <C> 2013/2014 Joerg Schwieder, use at will; I'd love to see an attribution, of course but don't demand it.
// Contains some pseudo code, see comments.
//
+ (CGFloat)blurRadius {
static CGFloat _blurRadius = 20.0;
static dispatch_once_t onceToken;
// I use different blur radius on iPad and iPhone
dispatch_once(&onceToken, ^{
if (IS_ON_PAD)
_blurRadius *= 2.0;
});
return _blurRadius;
}
+ (CGFloat)filteredSize {
static CGFloat _filteredSize = 320.0;
static dispatch_once_t onceToken;
// I use different image sizes on iPad and iPhone.
// This can, of course, be variable, too, it's being set dynamically on the filter for each run but that filter change takes some time
// I also use non-retina resolution because I felt that the lower resolution goes unnoticed (for the blurred image) on retina screens and it cuts the processing by 75%
dispatch_once(&onceToken, ^{
if (IS_ON_PAD)
_filteredSize = 768.0;
});
return _filteredSize;
}
+ (void)createBlurredImage:(UIImage *)art
withTintColor:(UIColor *)blendColor
desaturationFactor:(CGFloat)desaturationFactor
completion:(void(^)(UIImage * source, UIImage * result))completionHandler;
{
static CIFilter * ciBlurFilter;
static CIFilter * ciColorControlFilter;
static CIContext * ciContext;
static CIFilter * ciColorGenerator;
static CIFilter * ciCompositor;
static dispatch_queue_t filterQueue;
// this initializatuon code needs to be run on the main thread.
// I use a macro to determine which thread I'm on (I use specific queues I can identify at runtime).
// If you don't have that you could add the whole code to a custom class and simply initialize it before use
dispatch_sync_safe(dispatch_get_main_queue(), ^{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
ciContext = [CIContext contextWithOptions:nil];
ciBlurFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
ciColorControlFilter = [CIFilter filterWithName:@"CIColorControls"];
//[ciColorControlFilter setValue:@(desaturationFactor) forKey:@"inputSaturation"];
ciColorGenerator = [CIFilter filterWithName:@"CIConstantColorGenerator"];
ciCompositor = [CIFilter filterWithName:@"CISourceOverCompositing"];
filterQueue = dispatch_queue_create("ickBlurFilterQueue", NULL);
});
});
if (!art)
return;
if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
completionHandler(art, nil);
return;
}
dispatch_async(filterQueue, ^{
CIImage * ciImage = [CIImage imageWithCGImage:art.CGImage];
CIImage * result;
CGFloat scale = (art.size.width / [self filteredSize]);
CGFloat blurRadius = [self blurRadius];
CGRect rect = CGRectMake(-(2.0 * blurRadius) * scale,
-(2.0 * blurRadius) * scale,
scale * (4.0 * blurRadius) + art.size.width,
scale * (4.0 * blurRadius) + art.size.height);
UIColor * bgClear = [blendColor colorWithAlphaComponent:1.0];
CIColor * ciColor = [CIColor colorWithCGColor:bgClear.CGColor];
if (!ciImage || !bgClear || !ciColor) {
completionHandler(art, nil);
return;
}
[ciColorGenerator setValue:ciColor forKey:@"inputColor"];
[ciColorControlFilter setValue:@(desaturationFactor) forKey:@"inputSaturation"];
[ciColorControlFilter setValue:ciImage forKey:kCIInputImageKey];
blurRadius = blurRadius * scale;
[ciBlurFilter setValue:@(blurRadius) forKey:@"inputRadius"];
//NSLog(@"Image Size: %f %f, Blur Radius: %f", _coverImage.size.width, _coverImage.size.height, blurRadius);
// the compositor filter combines the generated color background and the desaturated image
[ciCompositor setValue:ciColorGenerator.outputImage forKey:@"inputBackgroundImage"];
[ciCompositor setValue:ciColorControlFilter.outputImage forKey:@"inputImage"];
// the blur filter takes the compositor output as input
[ciBlurFilter setValue:ciCompositor.outputImage forKey:kCIInputImageKey];
result = ciBlurFilter.outputImage;
if (!result) {
completionHandler(art, nil);
return;
}
CGImageRef cgImage = [ciContext createCGImage:result fromRect:rect];
UIImage * modImage = [UIImage imageWithCGImage:cgImage];
completionHandler(art, modImage);
CGImageRelease(cgImage);
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment