购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

3.1 使用图像

为了便于操作图像iOS中定义图像类,UIImage是UIKit框架中定义的图像类,其封装了高层次图像类,可以通过多种方式创建这些对象。在Core Graphics框架(或Quartz 2D)中也定义了CGImage,它表示位图图像,因为CGImage被封装起来了,所以通常通过CGImageRef来使用CGImage。

除了UIImage和CGImage外,在Core Image框架中也有一个图像类CIImage,CIImage封装的图像类能够很好地进行图像效果处理,例如,滤镜的使用。UIImage、CGImage和CIImage之间可以互相转化,这个过程中需要注意内存释放问题,特别是CGImage与UIImage之间转化,涉及从C变量到Objective-C对象转化,如果这里使用了ARC(Automatic Reference Counting,自动引用计数)技术,反而会使内存释放问题更复杂。随着后面的学习会逐步了解这些内存释放问题。

3.1.1 创建图像

本节介绍的创建图像主要是创建UIImage对象,CGImage一般不直接创建,因此不打算特意介绍了。CIImage对象创建在滤镜一节介绍,这一节中暂时不介绍。

下面介绍如何创建UIImage类图像对象。UIImage有一些构造方法和静态创建方法(即直接通过类名调用静态方法创建)。

对于上面介绍的方法可以根据图像来源的不同进行分类。在iOS设备中图像来源主要有以下4种不同渠道:

如果一个icon.png文件放在应用程序包中(资源文件)加载图像,可以通过下面的几种代码实现:

UIImage* image = [UIImage imageNamed:@"icon.png"];

NSString *path = [[NSBundle mainBundle] pathForResource:@"icon" ofType:@"png"];
UIImage* image = [UIImage imageWithContentsOfFile:path];

NSString *path = [[NSBundle mainBundle] pathForResource:@"icon" ofType:@"png"];
UIImage* image = [[UIImage alloc] initWithContentsOfFile:path];

NSString *path = [[NSBundle mainBundle] pathForResource:@"icon" ofType:@"png"];
NSData *data = [[NSData alloc] initWithContentsOfFile:path];
UIImage* image = [UIImage imageWithData:data];

NSString *path = [[NSBundle mainBundle] pathForResource:@"icon" ofType:@"png"];
NSData *data = [[NSData alloc] initWithContentsOfFile:path];
UIImage* image = [[UIImage alloc] initWithData:data];

如果icon.png文件放在应用程序沙箱目录中的Document目录下面,可以通过下面的几种代码实现:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, 
                                            NSUserDomainMask, YES);
NSString* path  = [[paths lastObject] 
                                    stringByAppendingPathComponent:@"icon.png"];
UIImage* image = [UIImage imageWithContentsOfFile:path];

NSArray *paths =  NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, 
                                            NSUserDomainMask, YES);
NSString* path  = [[paths lastObject] 
                                    stringByAppendingPathComponent:@"icon.png"];
UIImage* image = [[UIImage alloc] initWithContentsOfFile:path];

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, 
                                            NSUserDomainMask, YES);
NSString* path  = [[paths lastObject] 
                                    stringByAppendingPathComponent:@"icon.png"];
NSData *data = [[NSData alloc] initWithContentsOfFile:path];
UIImage* image = [UIImage imageWithData:data];

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, 
                                            NSUserDomainMask, YES);
NSString* path  = [[paths lastObject] 
                                    stringByAppendingPathComponent:@"icon.png"];
NSData *data = [[NSData alloc] initWithContentsOfFile:path];
UIImage* image = [[UIImage alloc] initWithData:data];

在上述代码中获得应用程序沙箱目录中Document目录语句如下:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, 
                                            NSUserDomainMask, YES);
NSString* path  = [[paths lastObject] 
                                    stringByAppendingPathComponent:@"icon.png"];

如果icon.png文件放在云服务器端http://xxx/icon.png下,可以通过如下的几种方式创建UIImage图像对象:

NSURL *url = [NSURL URLWithString:@"http://xxx/icon.png"];    
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
UIImage* image = [UIImage imageWithData:data];

NSURL *url = [NSURL URLWithString:@"http://xxx/icon.png"];    
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
UIImage* image = [[UIImage alloc] initWithData:data];

上述代码介绍了3种情况下创建图像对象,而从设备图片库或从照相机抓取后面章节介绍。

下面通过一个具体的实例介绍这3种创建图像方式。实例通过屏幕下方的3个按钮分别从3个不同的来源创建UIImage对象显示在屏幕上方,如图3-2所示。

图3-2 创建图像实例

首先使用Xcode选择Single View Application工程模板,创建一个ImageSample工程,并添加资源文件到工程中,具体的UI设计过程不再赘述,重点看看代码部分。其中视图控制器类ViewController.h代码如下所示。

#import <UIKit/UIKit.h>
#define FILE_NAME @"flower.png"

@interface ViewController: UIViewController

@property (retain, nonatomic) IBOutlet UIImageView *imageView;

- (IBAction)loadBundle:(id)sender;

- (IBAction)loadSandbox:(id)sender;

- (IBAction)loadWebService:(id)sender;

@end

视图控制器类ViewController.m文件代码如下所示。

#import "ViewController.h"

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //复制图片到沙箱目录下
    [self createEditableCopyOfDatabaseIfNeeded];
    
    _imageView.image = [UIImage imageNamed:@"SkyDrive340.png"];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

- (void)createEditableCopyOfDatabaseIfNeeded {
    
    NSFileManager *fileManager = [NSFileManager defaultManager];                        ①
    NSString *writableDBPath= [self applicationDocumentsDirectoryFile];                 ②
                                                                                          
    BOOL dbexits = [fileManager fileExistsAtPath:writableDBPath];                       ③
    if (!dbexits) {                                                                       
            NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath]          
                    stringByAppendingPathComponent:FILE_NAME];                           ④
        
            NSError *error;
            BOOL success = [fileManager copyItemAtPath:defaultDBPath 
                                toPath:writableDBPath error:&error];                 ⑤
            if (!success) {
                NSAssert1(0, @"错误写入文件:'%@'。", [error localizedDescription]);
            }
    }
}

- (NSString *)applicationDocumentsDirectoryFile {
    
  NSString *documentDirectory = 
            NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, 
                                    NSUserDomainMask, YES) lastObject];
    NSString *path 
        = [documentDirectory stringByAppendingPathComponent:FILE_NAME];
        return path;
}

- (IBAction)loadBundle:(id)sender {
    _imageView.image = [UIImage imageNamed:@"SkyDrive340.png"];
    NSString *path = [[NSBundle mainBundle] 
                                pathForResource:@"SkyDrive340" ofType:@"png"];    
    UIImage* image = [[UIImage alloc] initWithContentsOfFile:path];                   ⑥
    _imageView.image = [UIImage imageNamed:@"SkyDrive340.png"];
    [image release];
    
}

- (IBAction)loadSandbox:(id)sender {
    
    NSString *path = [self applicationDocumentsDirectoryFile];
    UIImage* image = [UIImage imageWithContentsOfFile:path];                            ⑦
    _imageView.image = image;
    
}

- (IBAction)loadWebService:(id)sender {
    
    NSURL *url = [NSURL URLWithString:@"http://iosbook3.com/service/download.php?email=<您的http://iosbook3.com网站注册邮箱>&FileName=2004-2OH.jpg"];                                                                           ⑧
    
    NSData *data = [[NSData alloc] initWithContentsOfURL:url];
    UIImage* image = [[UIImage alloc] initWithData:data];                             ⑨
    _imageView.image = image;
    
    [data release];
    [image release];
}


- (void)dealloc {
    [_imageView release];
    [super dealloc];
}

@end

上述代码中,viewDidLoad是视图加载方法,其中[self createEditableCopyOfDatabaseIfNeeded]语句是把资源文件中的图片复制到沙箱中Document目录下面,这是因为沙箱目录一开始没有任何图片。还有该方法中_imageView.image=[UIImage imageNamed:@"SkyDrive340.png"]语句是初始化显示SkyDrive340.png图片,这样启动应用时候就可以看到有一张图片显示在界面中,而不是空白界面。

在createEditableCopyOfDatabaseIfNeeded方法中,第①行代码[NSFileManager defaultManager]是获得NSFileManager实例,是采用单例设计模式实现的。第②行代码调用applicationDocumentsDirectoryFile方法获得沙箱目录,这个方法是自己编写的。第③行代码是沙箱目录下文件是否存在,如果文件不存在则通过第⑤行代码调用NSFileManager的copyItemAtPath:toPath:error:方法从应用程序包中复制一个图片文件到沙箱目录。第④行代码是获得应用程序包目录。

单击资源目录加载按钮触发-(IBAction)loadBundle:(id)sender方法。在该方法中第⑥行代码是通过UIImage的initWithContentsOfFile:方法从文件中创建图像对象。

单击沙箱目录加载按钮触发-(IBAction)loadSandbox:(id)sender方法。在该方法中第⑦行代码是通过imageWithContentsOfFile:方法从文件中创建图像对象。

单击云服务器加载按钮触发-(IBAction)loadWebService:(id)sender方法。其中第⑧行代码是请求服务器地址,其中<您的http://iosbook3.com网站注册邮箱>需要读者换成自己的注册邮箱,如果没有,请读者到iosbook3.com网站注册成为会员,然后把注册的邮箱替换<您的http://iosbook3.com网站注册邮箱>,这样iosbook3.com才能提供服务,客户端才能显示图片。第⑨行代码是通过initWithData:方法从服务器端取得数据来创建图像对象。

下面,可以运行以下实例,如图3-3所示。

图3-3 实例运行

3.1.2 从设备图片库选取或从照相机抓取

图像的另外一个重要来源是从设备图片库选取或从照相机抓取。UIKit中提供一个图像选择器UIImagePickerController,UIImagePickerController不仅可以实现选取图像还可以捕获视频信息。而且UIImagePickerController不仅可以从照相机中选取图像,还可以从相簿和相机胶卷中选择。相簿和相机胶卷是有区别的,相簿包含了相机胶卷,图3-4左所示是iPod touch(或iPhone)中的相簿,其中包含了相机胶卷、照片图库等内容,单击相机胶卷进入图3-4右所示是iPod touch(或iPhone)中的相机胶卷。相簿是可以查看所有图片,而相机胶卷是通过照相机拍摄或截屏获得的图片。

图3-4 iPod touch(或iPhone)中的照片应用

UIImagePickerController的主要属性是sourceType,sourceType属性是在枚举UIImage-PickerControllerSourceType中定义的3个常量:

UIImagePickerController委托对象需要实现UIImagePickerControllerDelegate委托协议。UIImagePickerControllerDelegate中定义了以下两个方法:

下面通过一个实例具体介绍图像选择器过程。如图3-5和图3-6所示是图像选择器实例,其中图3-5左图是实例启动的第一个界面,单击“从图片库中选取”按钮会从设备的图片库中选择图片(图3-5中),选择图片后回到开始界面,这时候选择的照片显示在屏幕上(图3-5右)。如果单击“从照相机中抓取”(图3-6左)按钮会从启动照相机预览(图3-6中),选择图片后回到开始界面,这时候选择的照片显示在屏幕上(图3-6右)。

图3-5 图像选择器实例(从图片库中选取)

图3-6 图像选择器实例(从照相机中抓取)

首先使用Xcode选择Single View Application工程模板,创建一个ImagePicker工程。具体的UI设计过程不再赘述,重点看看代码部分。其中视图控制器类ViewController.h代码如下所示。

#import <UIKit/UIKit.h>

@interface ViewController: UIViewController
    <UIImagePickerControllerDelegate,UINavigationControllerDelegate>              ①
                                                                                
@property (strong, nonatomic) UIImagePickerController *imagePicker;             ②

@property (retain, nonatomic) IBOutlet UIImageView *imageView;

- (IBAction)pickPhotoLibrary:(id)sender;

- (IBAction)pickPhotoCamera:(id)sender;
@end

在h文件的第①行代码声明实现UIImagePickerControllerDelegate和UINavigationControllerDelegate委托协议,其中UINavigationControllerDelegate也是UIImagePickerController的delegate属性要求实现的协议,UINavigationControllerDelegate协议定义了两个方法:

– navigationController:willShowViewController:animated:
– navigationController:didShowViewController:animated:

这两个方法是在抓取界面出现前后回调的方法。第②行代码UIImagePickerController *imagePicker定义了图像控制器的一个属性。

视图控制器类ViewController.m主要代码如下所示。

- (IBAction) pickPhotoCamera:(id)sender {                                            ①
    if ([UIImagePickerController isSourceTypeAvailable:
                UIImagePickerControllerSourceTypeCamera]) {    
        _imagePicker = [[UIImagePickerController alloc] init];     
        _imagePicker.delegate = self;                         
        _imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;     
        
        [self presentViewController:_imagePicker animated:YES completion:nil]; 
    } else {        
        NSLog(@"照相机不可用。");
    }
}

- (IBAction)pickPhotoLibrary:(id)sender {
    if (_imagePicker == nil) {
        _imagePicker = [[UIImagePickerController alloc] init];
    }
    _imagePicker.delegate = self;
    _imagePicker.sourceType 
                    = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
    
    [self presentViewController:_imagePicker animated:YES completion:nil];
}
- (void) imagePickerControllerDidCancel: (UIImagePickerController *) 
                picker {                                                             ②
        _imagePicker.delegate = nil;
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (void) imagePickerController: (UIImagePickerController *) picker
    didFinishPickingMediaWithInfo: (NSDictionary *) info {                           ③
    
    UIImage *originalImage = (UIImage *) [info objectForKey:
                                    UIImagePickerControllerOriginalImage];
    
    self.imageView.image = originalImage;
    self.imageView.contentMode = UIViewContentModeScaleAspectFill;    
    _imagePicker.delegate = nil;
    [self dismissViewControllerAnimated:YES completion:nil];
    
}

在上述代码中第①行pickPhotoCamera:方法是从照相机抓取图片的方法,第②行和第③行代码是实现UIImagePickerControllerDelegate协议方法。

下面详细说明pickPhotoCamera:和imagePickerController:didFinishPickingMediaWithInfo:方法。takeImage:代码如下。

- (IBAction) pickPhotoCamera:(id)sender { 
    if ([UIImagePickerController isSourceTypeAvailable:
                UIImagePickerControllerSourceTypeCamera]) {                           ①
        _imagePicker = [[UIImagePickerController alloc] init];                      ②
        _imagePicker.delegate = self;                                                  ③
        _imagePicker.sourceType 
                                    = UIImagePickerControllerSourceTypeCamera;         ④
        
        [self presentViewController:_imagePicker 
                                                animated:YES completion:nil];         ⑤
    } else {        
        NSLog(@"照相机不可用。");
    }
}

其中,第①行代码是通过UIImagePickerController的类方法isSourceTypeAvailable:法判断是否设备支持照相机图像源(UIImagePickerControllerSourceTypeCamera),如果是在iOS设备上运行该方法则返回true,如果是在模拟器上运行则返回值是false。

第②行代码是实例化UIImagePickerController对象。

第③行代码_imagePicker.delegate=self是指定UIImagePickerController的委托对象为当前视图控制器,注意委托对象要求实现UIImagePickerControllerDelegate和UINavigationControllerDelegate委托协议。

第④行代码_imagePicker.sourceType=UIImagePickerControllerSourceTypeCamera是指定UIImagePickerController对象的图像源为照相机。

第⑤行代码[self presentViewController:_imagePicker animated:YES completion:nil]是呈现系统提供的图像选择器界面。

imagePickerController:didFinishPickingMediaWithInfo:方法代码如下:

- (void) imagePickerController: (UIImagePickerController *) picker
    didFinishPickingMediaWithInfo: (NSDictionary *) info {        
    
    UIImage *originalImage = (UIImage *) [info objectForKey:
                                    UIImagePickerControllerOriginalImage];     ①
    
    self.imageView.image = originalImage;                                       ②
    self.imageView.contentMode = UIViewContentModeScaleAspectFill;              ③
    _imagePicker.delegate = nil;
    [self dismissViewControllerAnimated:YES completion:nil];                  ④

}

第①行代码是从参数info中取出原始图片数据,参数info如果抓取的是图片,则包含了原始或编辑后的图片数据,如果抓取的是视频,则包含的是视频存放路径。UIImagePickerControllerOriginalImage键是获取原始图片数据,此外常用的键还有

第②行代码self.imageView.image=originalImage是将从参数info中取出的图像对象保存到Image View控件上显示出来。

第③行代码self.imageView.contentMode=UIViewContentModeScaleAspectFill是设置Image View控件显示图像的方式,UIViewContentModeScaleAspectFill是缩放图像填充视图,有可能被裁减掉一些内容。

第④行代码[self dismissViewControllerAnimated:YES completion:nil]是关闭图像选择器界面。 A/+rNcnUnm+g2y8KpDVa+WIyv0L8cemhfXHNLf0m/eFLxaoWKf1aCWo4T2D5RKEq

点击中间区域
呼出菜单
上一章
目录
下一章
×