第十六章 iPhone照相机和照片库
应用程序可以通过“图像选取器”(image picker)来使用照相机和照片库。通常来说,图片选取器会使用图像列表做为他的源,不过也可以指定照相机做为源。
16.· 使用图像选取器和UIImagePickerController
图像选取器是通过名为UIImagePickerController的模式控制器类执行的。首先创建此类的一个实例,指定委托,并指定其图像源,然后以模式化方式启动他。图像选取器会控制iPhone让用户从已有的图像集中选择一副图片,或者使用照相机拍摄一副新图片。用户拍摄或者选择图像之后,就可以对所选图像进行一些基本的编辑,如缩放或裁剪。如果用户没有取消按钮,那么用户拍摄的或从库中选择的图像就会传到委托。
无论是否选择了图像,委托都有责任解除UIImagePickerController,让用户返回到应用程序。
创建UIImagePickerController非常简单,只需alloc] init,然而有一点需要注意,并不是每一台运行iPhone OS的设备都有照相机。iPhone Touch便是一个例子,但是将来,从Apple的装配线上出来的这样的设备会越来也少。在创建UIImagePickerController实例之前,需要先检查运行当前程序的设备是否支持要使用的图像源。例如,在用户可以使用照相机拍摄照片之前,应先确保程序所在的设备上有照相机。可以使用类方法检查UIImagePickerController,如:
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
在本例中,所传递的UIImagePickerControllerSourceTypePhotoLibrary表示我们想让用户使用现有照片库之外的照片。如果所指定的源当前可用,方法isSourceTypeAvailable:将返回YES。除了UIImagePickerControllerSourceTypePhotoLibrary之外,还可以指定另外两个值。
1)UIImagePickerControllerSourceTypeCamera 指定用户将使用内置的照相机拍摄图片,并将此图片返回到委托。
2)UIImagePickerControllerSourceTypeSavedPhotoAlbum 指定了用户将从现有照片库中选择图像,但选择范围仅限于最近的相册。此选项也可以在iPod Touch上运行,但是其作用不大。
在确保运行程序的设备支持要使用的图像源之后,启动图像选取器就相对容易多了:
UIImagePickerController *picker=[[UIImagePickerController alloc] init];
picker.delegate=self;
picker.sourceType=UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:picker animated:YES];
[picker release];
在创建并配置了UIImagePickerController之后,我们使用类从UIView中继承的presentModalViewController:animated:方法,将图像选取器呈现给用户。
提示:presentModalViewController:animted:方法并不仅限于呈现图像选取器,通过对当前可见视图的视图控制器调用此方法,可以按模式将任何视图控制器呈现给用户。
16.2 实现图像选取器控制器委托
用户退出图像选取器界面时,你希望获取的对象需要符合UIImagePickerControllerDelegate协议,此协议定义了两个方法,
1)imagePickerController:didFinishPickingImage:editingInfo: 第二个参数是包含用户所选照片的UIImage实例,第三个参数是一个NSDictionary实例,如果允许编辑,并且用户裁剪或缩放了图像,那么就会传递此参数。此字典存储在键UIImagePickerControllerOriginalImage下未编辑的原始图像。下面给出了检索原始图像的委托方法的一个例子:
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingImage:(UIImage *)image
editingInfo:(NSDictionary *)editingInfo {
UIImage *selectedImage=image;
UIImage *originalImage=[editingInfo objectForKey:UIImagePickerControllerOriginalImage];
//do something with selectedImage and originalImage
[picker dismissModalViewControllerAnimated:YES];
}
通过存储在键UIImagePickerControllerCropRect下的NSValue对象,editingInfo字典也可以指示在编辑期间选择了整个图像的哪一部分。也可以将此字符串转换至CGRect:
NSValue *cropRect=[editingInfo objectForKey:UIImagePickerControllerCropRect];
CGRect theRect=[cropRect CGRectValue];
完成转换之后,theRect可以指明在编辑过程中所选定的原始图像的部分。如果不需要此信息,则则可以忽略。
注意:如果返回到委托的图像来自照相机,那么此图像不会存储在照片库中。在必要时保存此图像的工作将由应用程序负责。
2)imagePickerControllerDidCancel:。
在UIImagePickerControllerDelegate协议中的两种方法都标记为可选,但实际上不是,原因是:必须通过本身解除图像选取器 这样的模式视图。因此,在用户取消图像选取器时,即使不需要采取任何应用程序特定的动作,也仍然需要解除选取器。至少,imagePickerControllerDidCancel:方法要像下面这样才能保证程序正确运行:
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[picker dismissModalViewControllerAnimated:YES];
}
16.3 实际测试照相机和库
在本章中,我们所构建的应用程序将允许用户使用照相机拍摄照片或从照片库选择一副图片,然后在图像视图中显示所选图片。如果用户的设备没有照相机,则隐藏Take Picture按钮和Pick from Library按钮,只允许从照片库中选择图片。
创建一个基于视图的新项目-Camera。
修改CameraViewController.h:
@interface CameraViewController:UIViewController <UIImagePickerControllerDelegate,UINavigationControllerDelegate> {
IBOutlet UIImageView *imageView;
IBOutlet UIButton *takePictureButton;
IBOutlet UIButton *selectFromCameraRollButton;
}
- (IBAction)getCameraPicture:(id)sender
- (IBAction)selectExistingPicture;
@end
需要注意,类必须遵循两个不同的协议:UIImagePickerControllerDelegate和UINavigationController。因为UIImagePickerController是UINavigationController的子类,所以必须遵循这两个协议。UINavigationControllerDelegate中的方法都是可选的,使用图像选取器不一定需要他们,但是必须要与此协议保持一致,否则编译器会发出警告。
16.3.1 设计界面
16.3.2 实现照相机视图控制器
- (void)viewDidLoad {
if (![UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeCamera]) {
takePictureButton.hidden=YES;
selectFromCameraRollButton.hidden=YES;
}
}
- (IBAction)getCameraPicker:(id)sender {
UIImagePickerController *picker=[[UIImagePickerController alloc] init];
picker.delegate=self;
picker.allowsImageEditing=YES;
picker.sourceType=(sender==takePictureButton)?UIImagePickerControllerSourceTypeCamera:UIImagePickerControllerSourceTypeSavedPhotosAlbum;
[self presentModalViewController:picker animated:YES];
[picker release];
}
- (IBAction)selectExistingPicture {
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
UIImagePickerController *picker=[[UIImagePickerController alloc] init];
picker.delegate=self;
picker.sourceType=UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:picker animated:YES];
[picker release];
}
else {
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"Error accessing phto library"
message:@"device does not support a photo library"
delegate:nil
cancelButton:@"Drat"
otherButtonTitles:nil];
[alert show];
[alert release];
}
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo {
imageView.view=image;
[picker dismissModalViewControllerAnimated:YES];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[picker dismissModalViewControllerAnimated:YES];
}
@end
所需要做的仅仅如此,甚至不需要链接其他库。仿真器上没有照相机,且照片库也是空的。如果有机会在实际设备上运行程序,请尝试继续操作。此时应该可以拍摄照片,并可以使用手指捏合的姿势放大和缩小图片。
如果在单击Use Photo按钮之前放大图片,则在委托方法中返回至应用程序的图像将会是裁剪后的图像。