How do I apply a CIFilter to a UIImage?
Asked Answered
C

2

7

My app is crashing when I attempt to apply a filter to my user-selected UIImage (It has been working fine without applying the filter). I added and imported the "CoreImage" framework to my project so I could create filters for user-selected images.

I am attempting to apply the filter by creating a category for UIImage (based on Apple's documentation, and then calling the corresponding method on the UIImage selected by the user. Following is the code of my category header and body; what am I doing wrong? (please note, "randColor" is a category UIColor class method to generate a random color)

#import <UIKit/UIKit.h>
#import <CoreImage/CoreImage.h>
#import "UIColor+CustomColorCategory.h"

@interface UIImage (MonoChromeFilter)

- (UIImage *) applyMonoChromeWithRandColor;

@end

#import "UIImage+MonoChromeFilter.h"

@implementation UIImage (MonoChromeFilter)

- (UIImage *)applyMonoChromeWithRandColor
{
    CIContext *context = [CIContext contextWithOptions:nil];

    CIImage *ciImage = [[CIImage alloc] initWithImage:self];

    CIFilter *filter = [CIFilter filterWithName:@"CIColorMonochrome"];

    [filter setValue:ciImage forKey:kCIInputImageKey];
    [filter setValue:[UIColor randColor] forKey:kCIAttributeTypeColor];

    CIImage *result = [filter valueForKey:kCIOutputImageKey];

    CGRect extent = [result extent];

    CGImageRef cgImage = [context createCGImage:result fromRect:extent];

    UIImage *filteredImage = [[UIImage alloc] initWithCGImage:cgImage];

    return filteredImage;
}

@end

Here is the method in the viewController where this category is being called:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    [picker dismissViewControllerAnimated:YES completion:^{
        UIImage *editedImage = [info objectForKey:UIImagePickerControllerEditedImage];
        editedImage = [editedImage applyMonoChromeWithRandColor];

        self.blogImageOutlet.image = editedImage;
        self.blogImageOutlet.layer.cornerRadius = self.blogImageOutlet.frame.size.width / 2.0;
        [self.blogImageOutlet setClipsToBounds:YES];

        [self saveImageToLibrary:editedImage];

    }];
}
Capybara answered 26/5, 2014 at 7:42 Comment(4)
Where is the use of this category ???Colosseum
what does the error in the crash says?Enforcement
The category is being applied to a UIView object in a View Controller. I will include the method where it is being called.Capybara
Here is the output of debug: 2014-05-26 00:52:08.052 Extending Class Functionality[676:60b] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<CIColorMonochrome 0x1700bdb80> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key CIAttributeTypeColor.' I suppose I know now that it's incorrect. What about this method is incorrect?Capybara
C
9

I figured it out! After debugging and using some other projects as a point of reference, I realized that I was experiencing two issues. First, I was trying to use a UIColor for CIColor, which is not directly possible. I first had to covert the UIColor to a CIColor to be able to apply it. Next, I was not using the correct strings for the CIFilter value keys. Here is the following code after modifications (and now it works!)

#import "UIImage+MonoChromeFilter.h"

@implementation UIImage (MonoChromeFilter)

+ (UIImage *) applyMonoChromeWithRandColor: (UIImage *)uIImage
{

    //  Convert UIColor to CIColor
    CGColorRef colorRef = [UIColor randColor].CGColor;
    NSString *colorString = [CIColor colorWithCGColor:colorRef].stringRepresentation;
    CIColor *coreColor = [CIColor colorWithString:colorString];

    CIContext *context = [CIContext contextWithOptions:nil];

    //  Convert UIImage to CIImage
    CIImage *ciImage = [[CIImage alloc] initWithImage:uIImage];

    //  Set values for CIColorMonochrome Filter
    CIFilter *filter = [CIFilter filterWithName:@"CIColorMonochrome"];
    [filter setValue:ciImage forKey:kCIInputImageKey];
    [filter setValue:@1.0 forKey:@"inputIntensity"];
    [filter setValue:coreColor forKey:@"inputColor"];

    CIImage *result = [filter valueForKey:kCIOutputImageKey];

    CGRect extent = [result extent];

    CGImageRef cgImage = [context createCGImage:result fromRect:extent];

    UIImage *filteredImage = [[UIImage alloc] initWithCGImage:cgImage];

    return filteredImage;
}

@end
Capybara answered 26/5, 2014 at 20:18 Comment(0)
D
0

Try This , It's work like champs for me ,

We have applied different CIFilter for single image,

Below is code for implementation ,

           //CISepiaTone Effect,

            CIContext *imageContext = [CIContext contextWithOptions:nil];
            CIImage *image = [[CIImage alloc]initWithImage:inputimage];
            CIFilter *filter = [CIFilter filterWithName:@"CISepiaTone"
                                          keysAndValues: kCIInputImageKey, image,
                                @"inputIntensity", @1, nil];

            CIImage *result = [filter valueForKey: @"outputImage"];
            CGImageRef cgImageRef = [imageContext createCGImage:result fromRect:[result extent]];
            UIImage *targetImage = [UIImage imageWithCGImage:cgImageRef];
            detailsVc.filterImage=targetImage;
            [self.navigationController pushViewController:detailsVc animated:YES];



            //CIVignette Effect 

            CIContext *imageContext = [CIContext contextWithOptions:nil];
            CIImage *image = [[CIImage alloc] initWithImage:inputimage];

            CIFilter *vignette = [CIFilter filterWithName:@"CIVignette"];
            [vignette setDefaults];
            [vignette setValue: image forKey: @"inputImage"];
            [vignette setValue: [NSNumber numberWithFloat: 1.0] forKey: @"inputIntensity"];
            [vignette setValue: [NSNumber numberWithFloat: 10.00 ] forKey: @"inputRadius"];

            CIImage *result = [vignette valueForKey: @"outputImage"];
            CGImageRef cgImageRef = [imageContext createCGImage:result fromRect:[result extent]];
            UIImage *targetImage = [UIImage imageWithCGImage:cgImageRef];
            detailsVc.filterImage=targetImage;
            [self.navigationController pushViewController:detailsVc animated:YES];

For detail implementation you can refer this GitHub project file ImageFilter

Hope so This will help for some one .

Detailed answered 30/8, 2017 at 7:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.