0

I'm getting an error on some code that two days ago was running fine. The error is:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFType extent]: unrecognized selector sent to instance 0x1bc8f0'

it points to this line on main.m:

return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));

Using logs to see where my code gets to it seems this line is throwing the error:

greySave = [context createCGImage:greyscaleImage fromRect:[greyscaleImage extent]];

greySave is a CGImageRef, declared at the start of my view controller. It's simple grabbing a CIImage output and converting it to a CGImageRef for saving:

desaturate = [CIFilter filterWithName:@"CIColorMonochrome" keysAndValues:kCIInputImageKey, colourSave, @"inputIntensity", [NSNumber numberWithFloat:0.00], nil];


greyscaleImage = [desaturate valueForKey:@"outputImage"];


greySave = [context createCGImage:greyscaleImage fromRect:[greyscaleImage extent]];

The only thing I have changed that I think (although do not understand why) could be causing the problem is adding an extra conditional statement, which would apply a second filter is the user wishes to do so:

if ([_alphaButtonSavedState isEqualToString:@"ON"]) {
             NSLog(@"user does want alpha on greyscale");
            //user wants alpha mask also  
        } else {
             NSLog(@"user does not want alpha on greyscale");
            //convert to CGImage for saving
            greySave = [context createCGImage:greyscaleImage fromRect:[greyscaleImage extent]];
             NSLog(@"greySave cgimage created");

            //save the grey image
            [library writeImageToSavedPhotosAlbum:greySave metadata:[greyscaleImage properties] completionBlock:^(NSURL *assetURL, NSError *error){
                if (error) {
                    NSLog(@"ERROR in greyscale save: %@", error);
                } else
                {
                    NSLog(@"SUCCESS in greyscale save");
                    //in here we'll put a nice animation or something
                    //CGImageRelease(greyscaleImage);
                }
            }];

Any ideas why this is happening?

Thanks.

EDIT:

Here is the entire chunk of code, just in case that helps.

[stillImage captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) {

    NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];  //get the raw image data from the session
    UIImage *startImage = [[UIImage alloc] initWithData:imageData];  //create a UIImage from that image data, let's us work with it

    //resizing of image to take place before anything else
    UIImage *image = [UIImage imageWithImage:startImage scaledToSize:_exportSSize];  //scale the image so it's shortest side is the size given in prefs

    NSLog(@"image width post scale: %g", image.size.width);
    NSLog(@"image height post scale is: %g", image.size.height);

    //change the context to render using cpu, so on app exit renders get completed
    context = [CIContext contextWithOptions: [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:kCIContextUseSoftwareRenderer]];

    //new crop testing - not using CIImage - seems to work, just need to sort out crop region
    CGRect cropRect = CGRectMake(0, 0, _exportSize, _exportSize);
    UIImage *cropper = [self imageByCropping:image toRect:cropRect];

    //the colour image is always saved so create a CGImage to save later
    colourSave = [cropper CGImage];
    NSLog(@"coloursave image created");

    //now we convert and create CGImages based upon chosen export options
    if ([_greyButtonSavedState isEqualToString:@"ON"]) {
        NSLog(@"inside the greyscale conditional");
        //user wants greyscale image
        //create a CIMonochrome filter 
        desaturate = [CIFilter filterWithName:@"CIColorMonochrome" keysAndValues:kCIInputImageKey, colourSave, @"inputIntensity", [NSNumber numberWithFloat:0.00], nil];
         NSLog(@"desat ci filter created");
        //get the output
        greyscaleImage = [desaturate valueForKey:@"outputImage"];
         NSLog(@"dest output image created");

        //if the user wants to add the alpha
        if ([_alphaButtonSavedState isEqualToString:@"ON"]) {
             NSLog(@"user does want alpha on greyscale");
            //user wants alpha mask also  
        } else {
             NSLog(@"user does not want alpha on greyscale");
            //convert to CGImage for saving
            greySave = [context createCGImage:greyscaleImage fromRect:[greyscaleImage extent]];
             NSLog(@"greySave cgimage created");

            //save the grey image
            [library writeImageToSavedPhotosAlbum:greySave metadata:[greyscaleImage properties] completionBlock:^(NSURL *assetURL, NSError *error){
                if (error) {
                    NSLog(@"ERROR in greyscale save: %@", error);
                } else
                {
                    NSLog(@"SUCCESS in greyscale save");
                    //in here we'll put a nice animation or something
                }
            }];
        }
    }

-- two more conditionals here, both currently empty

-- followed by a save for the colourSave image, this works fine.

-- then the method ends.

One more thing, this is how I'm cropping the image. The returned image from the following method is what I create a CIImage from:

-(UIImage *)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)rect

{ CGImageRef imageRef = CGImageCreateWithImageInRect([imageToCrop CGImage], rect);

UIImage *cropped = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);

return cropped;

}

mrEmpty
  • 841
  • 4
  • 19
  • 36
  • If it helps, the input image to the CIFilter is a UIImage. – mrEmpty May 12 '12 at 15:08
  • 1
    Can you put a breakpoint on the line where you create the `CGImage` and see what `greyscaleImage` is set to? The error is saying that the object `greyscaleImage` doesn't implement an `-extent` method. Could `greyscaleImage` either be nil or some other type of object? – user1118321 May 12 '12 at 15:13
  • 1
    @user1118321 logically, greyscaleImage is a CGImage because it inherits from NSCFType. It isn't nil, because then it wouldn't crash, as messages to nil produce nil. – CodaFi May 12 '12 at 15:25
  • I'm creating greyscaleImage as a CIImage: CIImage *greyscaleImage; As I say, this error did not occur before, using the same method to convert and save. The colour image saves. I'll post the entire code chunk as that may help. – mrEmpty May 12 '12 at 15:39
  • The conditional makes no difference, so I wonder if it has anything to do with the method I use to crop the image, shown here: -(UIImage *)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)rect { CGImageRef imageRef = CGImageCreateWithImageInRect([imageToCrop CGImage], rect); UIImage *cropped = [UIImage imageWithCGImage:imageRef]; CGImageRelease(imageRef); return cropped; } – mrEmpty May 12 '12 at 18:02
  • If I try to log the extent It throws the same error: greyscaleImage = [desaturate outputImage]; //get the output NSLog(@"dest output image created"); NSLog(@"greyscaleImage width is: %f", greyscaleImage.extent.size.width); NSLog(@"greyscaleImage height is: %f", greyscaleImage.extent.size.height); – mrEmpty May 12 '12 at 18:12
  • 1
    @user1118321 pointed me in the right direction, there was no extent because I was feeding a CGImage into a CIFilter, instead of a CIImage. No errors were thrown so I didn't spot it straight away. I'm now feeding a CIImage into the filter and converting the export, and all is good. I can now finish my app :) Just need to test test test and tweak tweak tweak. :) – mrEmpty May 12 '12 at 18:31

1 Answers1

8

Adding the answer in case it helps anyone else.

I was passing a UIImage into the CIFilter, this was causing the problem. Converting the UIImage into a CIImage and passing that in resolved the issue.

mrEmpty
  • 841
  • 4
  • 19
  • 36