Beginning Core Image in iOS 6

Note from Ray: This is the eighth iOS 6 tutorial in the iOS 6 Feast! In this tutorial, you’re updating one of our older tutorials to iOS 6 so it’s fully up-to-date with the latest features like the new Core Image filters in iOS 6. Parts of this tutorial come from Jake Gundersen‘s three Core […] By Jake Gundersen.

Leave a rating/review
Save for later
Share
You are currently viewing page 3 of 5 of this article. Click here to view the first page.

Getting Photos from the Photo Album

Now that you can change the values of the filter on the fly, things are starting to get real interesting! But what if you don’t care for this image of flowers? Let’s set up a UIImagePickerController so you can get pictures from out of the photo album and into your program so you can play with them.

You need to create a button that will bring up the photo album view, so open up ViewController.xib and drag in a button to the right of the slider and label it “Photo Album”.

Adding a button in the Storyboard editor

Then make sure the Assistant Editor is visible and displaying ViewController.h, then control-drag from the button down below the @interface. Set the Connection to Action, the name to loadPhoto, make sure that the Event is set to Touch Up Inside, and click Connect.

Next switch to ViewController.m, and implement the loadPhoto method as follows:

- (IBAction)loadPhoto:(id)sender {
    UIImagePickerController *pickerC = 
      [[UIImagePickerController alloc] init];
    pickerC.delegate = self;
    [self presentViewController:pickerC animated:YES completion:nil];
}

The first line of code instantiates a new UIImagePickerController. You then set the delegate of the image picker to self (our ViewController).

You get a warning here. You need to setup your ViewController as an UIImagePickerControllerDelegate and UINaviationControllerDelegate and then implement the methods in that delegates protocol.

Still in ViewController.m, change the class extension as follows:

@interface ViewController () <UIImagePickerControllerDelegate, UINavigationBarDelegate>
@end

Now implement the following two methods:

- (void)imagePickerController:(UIImagePickerController *)picker 
  didFinishPickingMediaWithInfo:(NSDictionary *)info {
    [self dismissViewControllerAnimated:YES completion:nil];
    NSLog(@"%@", info);
}

- (void)imagePickerControllerDidCancel:
  (UIImagePickerController *)picker {
    [self dismissViewControllerAnimated:YES completion:nil];
}

In both cases, you dismiss the UIPickerController. That’s the delegate’s job, if you don’t do it there, then you just stare at the image picker forever!

The first method isn’t completed yet – it’s just a placeholder to log out some information about chosen image. The cancel method just gets rid of the picker controller, and is fine as-is.

Compile and run and tap the button, and it will bring up the image picker with the photos in your photo album. If you are running this in the simulator, you probably won’t get any photos. On the simulator or on a device without a camera, you can use Safari to save images to your photo album. Open safari, find an image, tap and hold, and you’ll get a dialog to save that image. Next time you run your app, you’ll have it!

Here’s what you should see in the console after you’ve selected an image (something like this):

2012-09-20 17:30:52.561 CoreImageFun[3766:c07] {
    UIImagePickerControllerMediaType = "public.image";
    UIImagePickerControllerOriginalImage = "<UIImage: 0x71ecd00>";
    UIImagePickerControllerReferenceURL = "assets-library://asset/asset.JPG?
       id=253312C6-A454-45B4-A9DA-649126A76CA5&ext=JPG";
}

Note that it has an entry in the dictionary for the “original image” selected by the user. This is what you want to pull out and filter!

Now that we’ve got a way to select an image, how do you set your CIImage beganImage to use that image?

Simple, just change the delegate method to look like this:

- (void)imagePickerController:(UIImagePickerController *)picker
  didFinishPickingMediaWithInfo:(NSDictionary *)info {
    [self dismissViewControllerAnimated:YES completion:nil];
    UIImage *gotImage =
      [info objectForKey:UIImagePickerControllerOriginalImage];
    beginImage = [CIImage imageWithCGImage:gotImage.CGImage];
    [filter setValue:beginImage forKey:kCIInputImageKey];
    [self amountSliderValueChanged:self.amountSlider];
}

You need to create a new CIImage from your selected photo. You can get the UIImage representation of the photo by finding it in the dictionary of values, under the UIImagePickerControllerOriginalImage key constant. Note it’s better to use a constant rather than a hardcoded string, because Apple could change the name of the key in the future. For a full list of key constants, see the UIImagePickerController Delegate Protocol Reference.

You need to convert this into a CIImage, but you don’t have a method to convert a UIImage into a CIImage. However, you do have [CIImage imageWithCGImage:] method. You can get a CIImage from your UIImage by calling UIImage.CGImage, so you do exactly that!

You then set the key in the filter dictionary so that the input image is your new CIImage you just created.

The last line may seem odd. Remember how I pointed out that the code in the changeValue ran the filter with the latest value and updated the image view with the result?

Well you need to do that again, so you can just call the changeValue method. Even though the slider value hasn’t changed, you can still use that method’s code to get the job done. You could break that code into it’s own method, and if you were going to be working with more complexity, you would to avoid confusion. But, in this case your purpose here is served using the changeValue method. You pass in the amountSlider so that it has the correct value to use.

Compile and run, and now you’ll be able to update the image from your photo album!

Filtering a photo album image

What if you create the perfect sepia image, how do you hold on to it? You could take a screenshot, but you’re not that ghetto! Let’s learn how to save your photos back to the photo album.

Saving to Photo Album

To save to the photo album, you need to use the AssetsLibrary framework. To add it to your project, go to the project container, choose the Build Phases tab, expand the Link Binaries with Libraries group and click the + button. Find the AssetsLibrary framework, and add it.

Then add the following #import statement to the top of ViewController.m:

#import <AssetsLibrary/AssetsLibrary.h>

One thing you should know is that when you save a photo to the album, it’s a process that could continue even after you leave the app.

This could be a problem as the GPU stops whatever it’s doinng when you switch from one app to another. If the photo isn’t finished being saved, it won’t be there when you go looking for it later!

The solution to this is to use the CPU CIRendering context. The default is the GPU, and the GPU is much faster. You can create a second CIContext just for the purpose of saving this file.

Let’s add a new button to your app that will let us save the photo you are currently modifying with all the changes we’ve made. Open MainStoryboard add a new button labeled “Save to Album”:

Adding a new button for saving to the photo album

Then connect it to a new savePhoto: method, like you did last time.

Then switch to ViewController.m and implement the method as follows:

- (IBAction)savePhoto:(id)sender {
    // 1
    CIImage *saveToSave = [filter outputImage];
    // 2
    CIContext *softwareContext = [CIContext
                                  contextWithOptions:@{kCIContextUseSoftwareRenderer : @(YES)} ];
    // 3
    CGImageRef cgImg = [softwareContext createCGImage:saveToSave
                                             fromRect:[saveToSave extent]];
    // 4
    ALAssetsLibrary* library = [[ALAssetsLibrary alloc] init];
    [library writeImageToSavedPhotosAlbum:cgImg
                                 metadata:[saveToSave properties]
                          completionBlock:^(NSURL *assetURL, NSError *error) {
                              // 5
                              CGImageRelease(cgImg);
                          }];
}

In this code block you:

  1. Get the CIImage output from the filter.
  2. Create a new, software based CIContext
  3. Generate the CGImageRef.
  4. Save the CGImageRef to the photo library.
  5. Release the CGImage. That last step happens in a callback block so that it only fires after you’re done using it.

Compile and run the app (remember, on an actual device since you’re using software rendering), and now you can save that “perfect image” to your photo library so it’s preserved forever!

Jake Gundersen

Contributors

Jake Gundersen

Author

Over 300 content creators. Join our team.