Camera and Photo Library
iOS provides two technologies for taking pictures and movies.
- The UIImagePickerController class provides basic, customizable user interfaces for taking pictures and movies and for giving the user some simple editing capability for newly-captured media. Use an image picker controller when you do not require a fully-custom solution.
- The AV Foundation framework provides flexible and powerful classes you can use, along with UIKit, to create fully-customized still image or movie capture for your app.
Similarly, iOS provides two technologies for providing a user interface for picking saved pictures and movies from the user’s photo albums.
- Instantiate a UIImagePickerController object as a media browser to let the user pick an item from their photo library, using a basic, system-supplied user interface.
- Alternatively, you can create a fully-customized picture and movie browser using the Assets Library framework along with UIKit.
Taking Pictures and Movies
Taking a picture or movie with an image picker controller is a three part process that proceeds as an interplay between your code and the system:
- You instantiate and modally present a camera interface—an instance of the UIImagePickerController class.
- The system manages the camera interface and the user’s interaction with it. In typical use, the user either takes a picture or movie, or cancels the operation.
- The system invokes your image picker controller delegate object’s methods, which in turn handle the results of the user’s interaction. The delegate is also responsible for dismissing the camera interface.
The UIImagePickerController class supports portrait mode only. This class is intended to be used as-is and does not support subclassing. In iOS 3.1 and later, you can assign a custom view to the cameraOverlayView property and use that view to present additional information or to manage the interactions between the camera interface and your code.
Creating and Configuring a Camera Interface
To present a camera interface, you must first ensure that three things are in place:
- .f taking pictures or movies is essential to your app, specify that by configuring the UIRequiredDeviceCapabilities key in your app’s Info.plist property list file.
- The device’s camera must be available for you to use, which you can test by way of the isSourceTypeAvailable: class method of the UIImagePickerController class.
- You must have implemented a delegate object to respond to the user’s interaction with the image picker controller.
With those prerequisites satisfied, create and then configure an image picker controller by specifying the following options:
- Source type To configure the picker for media capture as opposed to browsing saved media, set its sourceType property to UIImagePickerControllerSourceTypeCamera.
- Media types To specify whether the user can take still images, movies, or both, set the mediaTypes property to an array containing identifiers for the desired types. The valid values for elements of the array are kUTTypeImage and kUTTypeMovie. However, before setting this property, check which media types are available by calling the availableMediaTypesForSourceType: class method.
- Editing controls Set the allowsEditing property to YES (to provide editing controls) or to NO.When using built-in editing controls, the image picker controller enforces certain options.
- Delegate object Finally, assign your delegate object to the image picker controller’s delegate property.
- (BOOL) startCameraControllerFromViewController: (UIViewController*) controller
usingDelegate: (id <UIImagePickerControllerDelegate,
UINavigationControllerDelegate>) delegate {
if (([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeCamera] == NO)
|| (delegate == nil)
|| (controller == nil))
return NO;
UIImagePickerController *cameraUI = [[UIImagePickerController alloc] init];
cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera;
// Displays a control that allows the user to choose picture or
// movie capture, if both are available:
cameraUI.mediaTypes =
[UIImagePickerController availableMediaTypesForSourceType:
UIImagePickerControllerSourceTypeCamera];
// Hides the controls for moving & scaling pictures, or for
// trimming movies. To instead show the controls, use YES.
cameraUI.allowsEditing = NO;
cameraUI.delegate = delegate;
[controller presentModalViewController: cameraUI animated: YES];
return YES;
}
To instead present a picker that captures only movies, for example, ensure that movie capture is available and then set the mediaTypes property as follows:
cameraUI.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeMovie, nil];
For a picker that captures only still images, replace the kUTTypeMovie identifier here with kUTTypeImage, or rely on the default value of the mediaTypes property, which is kUTTypeImage.
Delegate object must conform to the UIImagePickerControllerDelegate and UINavigationControllerDelegate protocols.
Implementing a Delegate for the Camera Interface
1. The delegate must dismiss it by calling the dismissModalViewControllerAnimated: method and must release the interface as well.
2. The imagePickerController:didFinishPickingMediaWithInfo: implementation includes code for saving a still image or a movie, depending on what the user captured.
Listing 2 Delegate methods for a camera interface
@implementation CameraViewController (CameraDelegateMethods)
// For responding to the user tapping Cancel.
- (void) imagePickerControllerDidCancel: (UIImagePickerController *) picker {
[[picker parentViewController] dismissModalViewControllerAnimated: YES];
[picker release];
}
// For responding to the user accepting a newly-captured picture or movie
- (void) imagePickerController: (UIImagePickerController *) picker
didFinishPickingMediaWithInfo: (NSDictionary *) info {
NSString *mediaType = [info objectForKey: UIImagePickerControllerMediaType];
UIImage *originalImage, *editedImage, *imageToSave;
// Handle a still image capture
if (CFStringCompare ((CFStringRef) mediaType, kUTTypeImage, 0)
== kCFCompareEqualTo) {
editedImage = (UIImage *) [info objectForKey:
UIImagePickerControllerEditedImage];
originalImage = (UIImage *) [info objectForKey:
UIImagePickerControllerOriginalImage];
if (editedImage) {
imageToSave = editedImage;
} else {
imageToSave = originalImage;
}
// Save the new image (original or edited) to the Camera Roll
UIImageWriteToSavedPhotosAlbum (imageToSave, nil, nil , nil);
}
// Handle a movie capture
if (CFStringCompare ((CFStringRef) mediaType, kUTTypeMovie, 0)
== kCFCompareEqualTo) {
NSString *moviePath = [[info objectForKey:
UIImagePickerControllerMediaURL] path];
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum (moviePath)) {
UISaveVideoAtPathToSavedPhotosAlbum (
moviePath, nil, nil, nil);
}
}
[[picker parentViewController] dismissModalViewControllerAnimated: YES];
[picker release];
}
@end
Picking an Item from the Photo Library
You can use UIImagePickerController to present a media browser that lets a user choose an item from their saved photo albums.
- Instead of using the camera as the media source, you use the Camera Roll album or Saved Photos album, or the entire photo library.
- Instead of capturing new media and (typically) saving it to an album, you let the user pick previously-saved media. You can then use the picked media in your app, perhaps displaying it full screen.
Creating and Configuring a Media Browser
You can then instantiate and configure an image picker controller by specifying the following options:
- Source type To configure the picker for browsing saved media as opposed to capturing a new picture or movie, set its sourceType property to one of the saved photo sources:
- Use UIImagePickerControllerSourceTypePhotoLibrary to present a browser that provides access to all the photo albums on the device, including the Camera Roll album on devices that have a camera.
- Use UIImagePickerControllerSourceTypeSavedPhotosAlbum to present a browser that restricts access to the Camera Roll album on devices that have a camera, or to the Saved Photos album on devices that don’t.
Note: As you do for the camera picker, always call the isSourceTypeAvailable: class method of the UIImagePickerController class and respect its return value. Never assume that a device has a photo library. Even if the device has a library, this method could still return NO if the library is currently unavailable
- Media types To specify whether the image picker controller displays saved movies, still images, or both, set the mediaTypes property to an array containing identifiers for the desired types. The valid values for elements of the array are kUTTypeImage and kUTTypeMovie.However, before setting this property, check which media types are available by calling the availableMediaTypesForSourceType: class method.
- Editing controls Set the allowsEditing property to YES (to provide editing controls) or to NO.
- Delegate object Finally, assign your delegate object to the image picker controller’s delegate property.
Listing 1 Presenting the media browser interface full screen
- (BOOL) startMediaBrowserFromViewController: (UIViewController*) controller
usingDelegate: (id <UIImagePickerControllerDelegate,
UINavigationControllerDelegate>) delegate {
if (([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeSavedPhotosAlbum] == NO)
|| (delegate == nil)
|| (controller == nil))
return NO;
UIImagePickerController *mediaUI = [[UIImagePickerController alloc] init];
mediaUI.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
// Displays saved pictures and movies, if both are available, from the
// Camera Roll album.
mediaUI.mediaTypes =
[UIImagePickerController availableMediaTypesForSourceType:
UIImagePickerControllerSourceTypeSavedPhotosAlbum];
// Hides the controls for moving & scaling pictures, or for
// trimming movies. To instead show the controls, use YES.
mediaUI.allowsEditing = NO;
mediaUI.delegate = delegate;
[controller presentModalViewController: mediaUI animated: YES];
return YES;
}
Implementing a Delegate for the Media Browser
If the user taps a thumbnail, what happens next depends on whether the thumbnail represents a still image or a move.
- For still images, tapping the thumbnail immediately calls the delegate with information about the image.
- For movies, tapping the thumbnail displays a preview with a scroller plus three buttons: play, Cancel, and Choose. If the user taps Choose, the system calls the delegate with information about the movie. If the user taps Cancel, the preview automatically dismisses and returns the user to the media browser.
Listing 2 Delegate method for picked media
- (void) imagePickerController: (UIImagePickerController *) picker
didFinishPickingMediaWithInfo: (NSDictionary *) info {
NSString *mediaType = [info objectForKey: UIImagePickerControllerMediaType];
UIImage *originalImage, *editedImage, *imageToUse;
// Handle a still image picked from a photo album
if (CFStringCompare ((CFStringRef) mediaType, kUTTypeImage, 0)
== kCFCompareEqualTo) {
editedImage = (UIImage *) [info objectForKey:
UIImagePickerControllerEditedImage];
originalImage = (UIImage *) [info objectForKey:
UIImagePickerControllerOriginalImage];
if (editedImage) {
imageToUse = editedImage;
} else {
imageToUse = originalImage;
}
// Do something with imageToUse
}
// Handle a movied picked from a photo album
if (CFStringCompare ((CFStringRef) mediaType, kUTTypeMovie, 0)
== kCFCompareEqualTo) {
NSString *moviePath = [[info objectForKey:
UIImagePickerControllerMediaURL] path];
// Do something with the picked movie available at moviePath
}
[[picker parentViewController] dismissModalViewControllerAnimated: YES];
[picker release];
}