Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CIFilter guassianBlur and boxBlur are shrinking the image - how to avoid the resizing?

I am taking a snapshot of the contents of an NSView, applying a CIFilter, and placing the result back into the view. If the CIFilter is a form of blur, such as CIBoxBlur or CIGuassianBlur, the filtered result is slightly smaller than the original. As I am doing this iteratively the result becomes increasingly small, which I want to avoid.

The issue is alluded to here albeit in a slightly different context (Quartz Composer). Apple FunHouse demo app applies a Guassian blur without the image shrinking, but I haven't yet worked out how this app does it (it seems to be using OpenGL which I am not familiar with).

Here is the relevant part of the code (inside an NSView subclass)

NSImage* background = [[NSImage alloc] initWithData:[self dataWithPDFInsideRect:[self bounds]]];

CIContext* context = [[NSGraphicsContext currentContext] CIContext];
CIImage* ciImage = [background ciImage];

 CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"
 keysAndValues: kCIInputImageKey, ciImage,
 @"inputRadius", [NSNumber numberWithFloat:10.0], nil];

CIImage *result = [filter valueForKey:kCIOutputImageKey];
CGImageRef cgImage = [context createCGImage:result
                                   fromRect:[result extent]];

NSImage* newBackground = [[NSImage alloc] initWithCGImage:cgImage size:background.size];

If I try a color-changing filter such as CISepiaTone, which is not shifting pixels around, the shrinking does not occur.

I am wondering if there is a quick fix that doesn't involve diving into openGL?

like image 566
foundry Avatar asked Nov 19 '12 03:11

foundry


2 Answers

They're actually not shrinking the image, they're expanding it (I think by 7 pixels around all edges) and the default UIView 'scale To View' makes it looks like it's been shrunk.

Crop your CIImage with:

CIImage *cropped=[output imageByCroppingToRect:CGRectMake(0, 0, view.bounds.size.width*scale, view.bounds.size.height*scale)];

where view is the original bounds of your NSView that you drew into and 'scale' is your [UIScreen mainScreen] scale].

like image 129
BBC_Z Avatar answered Oct 11 '22 04:10

BBC_Z


@BBC_Z's solution is correct.

Although I find it more elegant to crop not according to the view, but to the image.
And you can cut away the useless blurred edges:

// Crop transparent edges from blur
resultImage = [resultImage imageByCroppingToRect:(CGRect){
    .origin.x = blurRadius,
    .origin.y = blurRadius,
    .size.width = originalCIImage.extent.size.width - blurRadius*2,
    .size.height = originalCIImage.extent.size.height - blurRadius*2
}];
like image 41
IluTov Avatar answered Oct 11 '22 03:10

IluTov