照相机和图片库(2)

来源:互联网 发布:mcgs组态软件视频教程 编辑:程序博客网 时间:2024/05/01 22:02

6.从多媒体库中获得图片和视频

6.1. 问题

 你希望用户可以从多媒体库中选择一个图片或者视频以在程序中使用。 

6.2. 方案

   通过使用 UIImagePickerController 这个类的来实现相关的功能,把源类型设置为 UIImagePickerControllerSourceTypePhotoLibrary,已经媒体类型选择 kUTTypeImage 或 kUTTypeMovie(或都选)。代码如下。 

- (BOOL)isPhotoLibraryAvailable{

    return [UIImagePickerControllerisSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary];

}

- (BOOL)canUserPickVideoFromPhotoLibarary{

    NSArray *array = [UIImagePickerControlleravailableMediaTypesForSourceType:UIImagePickerControllerSourceTypePhotoLibrary];

    __block BOOL result =NO;

    [array enumerateObjectsUsingBlock:^(id obj,NSUInteger idx,BOOL *stop) {

        NSString *mediaType = (NSString *)obj;

        if ([mediaType isEqualToString:(__bridge NSString *)kUTTypeMovie]) {

            result = YES;

            *stop = YES;

        }

    }];

    return result;

}

- (BOOL) canUserPickPhotosFromPhotoLibrary{

    //这里没有将两个方法合并

    NSArray *array = [UIImagePickerControlleravailableMediaTypesForSourceType:UIImagePickerControllerSourceTypePhotoLibrary];

    __block BOOL result =NO;

    [array enumerateObjectsUsingBlock:^(id obj,NSUInteger idx,BOOL *stop) {

        NSString *mediaType = (NSString *)obj;

        if ([mediaType isEqualToString:(__bridge NSString *)kUTTypeImage]) {

            result = YES;

            *stop = YES;

        }

    }];

    return result;

}

- (void)viewDidLoad {

    [superviewDidLoad];

    if ([selfisPhotoLibraryAvailable]) {

        controller = [[UIImagePickerControlleralloc]init];

        controller.sourceType =UIImagePickerControllerSourceTypePhotoLibrary;

        NSMutableArray *mediaTypes = [[NSMutableArrayalloc]init];

        if ([selfcanUserPickPhotosFromPhotoLibrary]) {

            [mediaTypes addObject:(__bridgeNSString *)kUTTypeImage];

        }

        if ([selfcanUserPickVideoFromPhotoLibarary]) {

            [mediaTypes addObject:(__bridgeNSString *)kUTTypeVideo];

        }

        controller.mediaTypes = mediaTypes;

        controller.delegate =self;

        

        UIButton *button = [UIButtonbuttonWithType:UIButtonTypeSystem];

        [button setTitle:@"选择资源"forState:UIControlStateNormal];

        [button addTarget:selfaction:@selector(pushUIImagePickerController)forControlEvents:UIControlEventTouchUpInside];

    }

    

}

- (void)pushUIImagePickerController{

    [selfpresentViewController:controlleranimated:YEScompletion:nil];

}


为了能够让用户选择图片或者是视频,必须在 UIImagePickerController 显示之前, UIImagePickerController 的 sourceType 属性设置为 UIImagePickerControllerSourceTypePhotoLibrary。另外,如果你希望对视频和图片进行过 滤,那么将 mediaTypes 属性设置为 kUTTypeMovie 或 kUTTypeImage。

 

记住,如果把 UIImagePickerController 的 mediaTypes 属性设置为 nil 或者一个空的数组,则会引发一个运行时错误。

当用户完成图片选择之后,通过 UIImagePickerControllerDelegate 协议你将收到消息来处理得到的图片或视频,参考上面第二节提到的.



7.从资源库中直接获取资源

7.1. 问题

 你希望从 Photo 库中直接获取图片或视频,而不通过内置的 GUI 组件。 

7.2. 方案

利用 Assets Library framework 这个框架,按照如下步骤进行:
1、分配和初始化一个 ALAssetsLibrary 类型的对象。

2、为 ALAssetsLibrary 对象的 enumerateGroupsWithTypes:usingBlock:failureBlock 方法提供两个 block 参数。第一个将会获取到所有指定类型相关的群组。群组的类型为 ALAssetsGroup。如果遇到错误,第二个 block 则会返回一个错误。

3、使用每个群组对象的 enumerateAssetsUsingBlock:实例方法来枚举出每个群组中的资源。这个方法将接收一个 block 作为参数,用来获取单个资源。传入的这个 block 必须接收 3 个参数,并且第一个参数必须是 ALAsset 类型。 

4、获取到每个群组中的 ALAsset 对象之后,就可以获取每个 asset 的属性了,包括它的 类型,可用 URLs 等。可以通过 ALAsset 的 valueForProperty:实例方法来获取这些属性。这 个方法返回的值取决于传入的属性,可能是 NSDictionary,NSString 或其它对象。稍后我们 会看到每个 asset 都有的一些通用属性。

5、调用 ALAsset 的 defaultRepresentation 实例方法来获取到它的表示对象:类型为 ALAssetRepresentation。每个 asset 都可以有多个表示对象。例如,一个图片默认情况下可以 是 PNG,不过也可以用 JPEG 来表示。使用 ALAsset 的 defaultRepresentation 方法可以获取 到一个 ALAssetRepresentation 对象。

6、使用 size 和 asset 的 getBytes:fromOffset:length:error:实例方法可以加载 asset 的表示 数据。然后你可以将读取到的 bytes 写入 NSData 对象中,或者做任意你想做的操作。另 外,针对图片,还可以使用每个 ALAssetRepresentation 的 fullResolutionImage, fullScreen

Image 和 CGImageWithOptions:实例方法来获取 CGImageRef 类型图片。然后使用 UIImage 的 imageWithCGImage:类方法来从 CGImageRef 中构造一个 UIImage。 





7.3. 讨论
Assets 库被分为不同的群组。每个群组包含 assets,而每个 asset 有属性,比如 URLs 和 representation 对象。

将 ALAssetsGroupAll 传入到 Assets 库实例方法 enumerateGroupsWithTypes:usingBlock:failureBlock:的 enumerateGroupsWithTypes 参数中,就可以获得所有类型的所有的 assets。下面列出来的值当做参数传入到上面的方法中,以枚举出 asset 的不同群组:

ALAssetsGroupAlbum
这个群组代表了通过 iTunes 存储到 iOS 设备上的相册。

ALAssetsGroupFaces
这个群组代表的相册是通过 iTunes 存储到 iOS 设备上的 face assets。

ALAssetsGroupSavedPhotos
这个群组代表了存储到 Photo 库中的图片。通过 Photo 程序也可以访问到。

ALAssetsGroupAll
在 Assets 库中所有可用的群组。 


a.

下面我们来写一个简单的示例,用来获取 Assets 库中第一个图片的数据,并创建一个 UIImageView,然后将其添加到当前 view control 的 view 上。这样,我们就可以学习到如何 使用 asset 的 representation 来读取其中的内容。

  现在我们需要做的就是当这个 viewcontroller 加载的时候,我们需要初始化一个 AssetSLibrary 的对象。然后开始枚举这个 asset 库,直到找到第一个图片。这时,我们将使 用 asset 的 representation 来将图片显示在 imageview 上: 

 

- (void)getOneImageFromAsset{

    self.assetsLibrary = [[ALAssetsLibraryalloc]init];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

        [self.assetsLibraryenumerateGroupsWithTypes:ALAssetsGroupAllusingBlock:^(ALAssetsGroup *group,BOOL *stop) {

            [group enumerateAssetsUsingBlock:^(ALAsset *result,NSUInteger index,BOOL *stop) {

                __block BOOL foundThePhoto = NO;

                if (foundThePhoto) {

                    *stop = YES;

                }

                //Get the asset type

                NSString *assetType = [result valueForProperty:ALAssetPropertyType];

                if ([assetType isEqualToString:ALAssetTypePhoto]) {

                    NSLog(@"This is a photo asset");

                    foundThePhoto = YES;

                    *stop = YES;

                    //get the asset's representation object

                    ALAssetRepresentation *assetRepresentation = [resultdefaultRepresentation];

                    /* We need the scale and orientation to be able to construct a properly oriented and scaled UIImage out of the representation object */

                    CGFloat imageScale = [assetRepresentationscale];

                    UIImageOrientation imageOrientation = (UIImageOrientation)[assetRepresentationorientation];

                    dispatch_async(dispatch_get_main_queue(), ^{

                        CGImageRef imageReference = [assetRepresentationfullResolutionImage];

                        //Construct the image now

                        UIImage *image = [[UIImagealloc]initWithCGImage:imageReferencescale:imageScaleorientation:imageOrientation];

                        if (image != nil) {

                            self.imageView = [[UIImageViewalloc]initWithFrame:self.view.bounds];

                            self.imageView.contentMode =UIViewContentModeScaleAspectFit;

                            self.imageView.image = image;

                            [self.viewaddSubview:self.imageView];

                        }

                    });

                }

            }];

        } failureBlock:^(NSError *error){

            NSLog(@"Failed to enumerate the asset groups.");

        }];

    });

}


上面的代码会对 asset 库进行枚举。获得第一个图片后,将得到它的 representation。通过这个 representation,我们创建一个 UIImage,然后创建一个 UIImageView 来显示图片。非常简单,不是吗?

 

b.

针对视频文件,处理过程有一些不同,因为 ALAssetRepresentation 类没有任何方法可以 返回关于视频文件的对象。因此,我们需要将视频文件内容读取到一个 buffer 中,然后将其 保存到 Documents 文件目录中。当然,这也取决于你的程序。在这里的示例代码中,我将找 出第一个视频文件,然后将其存储到程序的 Documents 目录下,文件命名为 Temp.MOV: 

- (void)getOneVideoFromAsset{

    self.assetsLibrary = [[ALAssetsLibraryalloc]init];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

        [self.assetsLibraryenumerateGroupsWithTypes:ALAssetsGroupAllusingBlock:^(ALAssetsGroup *group,BOOL *stop) {

            __block BOOL foundTheVideo = NO;

            [group enumerateAssetsUsingBlock:^(ALAsset *result,NSUInteger index,BOOL *stop) {

                //得到asset的类型

                NSString *assetType = [result valueForProperty:ALAssetPropertyType];

                if ([assetType isEqualToString:ALAssetTypeVideo]) {

                    NSLog(@"This is a video asset");

                    foundTheVideo = YES;

                    *stop = YES;

                    //如果是video类型的,并且得到assetrepresentation

                    ALAssetRepresentation *assetRepresentation = [resultdefaultRepresentation];

                    const NSUInteger BufferSize = 1024;

                    uint8_t buffer[BufferSize];

                    NSUInteger bytesRead = 0;

                    long long currentOffset = 0;

                    NSError *readingError = nil;

                    //选择存储视频的路径

                    NSArray *documents =NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory,NSUserDomainMask,YES);

                    //创建存储视频的文件

                    NSString *videoPath = [[documentsobjectAtIndex:0]stringByAppendingPathComponent:@"Temp.MOV"];

                    NSFileManager *fileManager = [[NSFileManageralloc]init];

                    //如果不存在,创建该文件

                    if ([fileManager fileExistsAtPath:videoPath] == NO) {

                        [fileManager createFileAtPath:videoPathcontents:nilattributes:nil];

                    }

                    //用文件句柄将media assets的数据写入磁盘

                    NSFileHandle *fileHandle = [NSFileHandlefileHandleForWritingAtPath:videoPath];

                    do {

                        /* Read as many bytes as we can put in the buffer */

                        bytesRead = [assetRepresentation getBytes:(uint8_t *)&buffer

                                                       fromOffset:currentOffset

                                                           length:BufferSize

                                                            error:&readingError];

                        /* If we couldn't read anything, we will exit this loop */

                        if (bytesRead == 0) {

                            break;

                        }

                        //Keep the offset up to date

                        currentOffset += bytesRead;

                        //Put the buffer into an NSData

                        NSData *readData = [[NSDataalloc]initWithBytes:(constvoid *)buffer length:bytesRead];

                        //write the data to file

                        [fileHandle writeData:readData];

                    } while (bytesRead > 0);

                    NSLog(@"Finished reading and storing the video in the documents folder");

                }

                

            }];

            if (foundTheVideo) {

                *stop = YES;

            }

        } failureBlock:^(NSError *error) {

            NSLog(@"Failed to enumerate the asset groups.");

        }];

    });

}


上面的代码会发生如下事情:
   1.获取第一个视频的默认 representation

  2.在程序的 Documents 目录下创建一个 Temp.MOV 文件,用来存储视频内容。

  3.创建一个循环。Asset representation 的实例方法 getBytes:fromOffset:length:error:尽可能多的将视频内容读取到 buffer 中,直到读取完毕。

  4.在将数据读取到 buffer 中后,使用 NSData 的初始化方法 initWithBytes:length:将数据封装为 NSData 对象。然后使用 NSFileHandle 的 writeData:实例方法将这些数据写入 到之前创建的文件中。 




8.在iOS设备中编辑视频
8.1. 问题 

你希望用户可以在你的程序中对视频直接进行编辑. 

8.2. 方案

通过使用 UIVideoEditorController 这个类。在这里给出的实例中,我们将会利用这个类 和 imagePickercontroleller 来共同解决这个问题,我们会先让用户从多媒体库中选择一个视频 文件,然后我们把这个文件加载在 UIVideoEditorController 中让用户来编辑。 

8.3. 讨论

iOS SDK 的 UIVideoEditorController 这个类可以为用户提供展示编辑视频的相关 UI 界面。你所需要做的就是只需要提供视频的 URL 连接地址。你不应该在这个 View 上面添加其他的什么视图,并且你不能修改这个视图。 


要遵守UIVideoEditorControllerDelegate协议

#pragma mark - video editor delegate

- (void)videoEditorController:(UIVideoEditorController *)editor didSaveEditedVideoToPath:(NSString *)editedVideoPath{

    NSLog(@"The video editor finished saving video");

    NSLog(@"The edited video path is at = %@", editedVideoPath);

    [editor dismissViewControllerAnimated:YEScompletion:nil];

}

- (void)videoEditorController:(UIVideoEditorController *)editor didFailWithError:(NSError *)error{

    NSLog(@"Video editor error occurred = %@", error);

    [editor dismissViewControllerAnimated:YEScompletion:nil];

}

- (void)videoEditorControllerDidCancel:(UIVideoEditorController *)editor{

    NSLog(@"The video editor was cancelled");

    [editor dismissViewControllerAnimated:YEScompletion:nil];

}


//当我们的视图加载时,我们需要给用户显示一个 video选取器,这样用户才能从媒体库中选择一个 video。然后才让用户进行编辑这个 video:

- (BOOL)cameraSupportsMedia:(NSString *)paramMediaType sourceType:(UIImagePickerControllerSourceType)paramSourceType{

    __block BOOL result =NO;

    if ([paramMediaType length] == 0) {

        NSLog(@"Media type is empty");

        return NO;

    }

    NSArray *availableMediaTypes = [UIImagePickerControlleravailableMediaTypesForSourceType:paramSourceType];

    [availableMediaTypes enumerateObjectsUsingBlock:^(id obj,NSUInteger idx, BOOL *stop) {

        NSString *mediaType = (NSString *)obj;

        if ([mediaType isEqualToString:paramMediaType]) {

            result = YES;

            *stop = YES;

        }

    }];

    return result;

}

- (BOOL)canUserPickVideosFromPhotoLibrary{

    return [selfcameraSupportsMedia:(__bridgeNSString *)kUTTypeMoviesourceType:UIImagePickerControllerSourceTypePhotoLibrary];

}

- (void)xianshi{

    if ([selfisPhotoLibraryAvailable] && [selfcanUserPickVideosFromPhotoLibrary]) {

        UIImagePickerController *imagePicker = [[UIImagePickerControlleralloc]init];

        imagePicker.sourceType =UIImagePickerControllerSourceTypePhotoLibrary;

        NSArray *mediaType = [[NSArrayalloc]initWithObjects:(__bridgeNSString *)kUTTypeMovie,nil];

        imagePicker.mediaTypes = mediaType;

        imagePicker.delegate = self;

        [selfpresentViewController:imagePicker animated:YEScompletion:nil];

    }

}

//现在当用户完成 video 选取时,我们需要知道,所以我们来处理一下 image picker协议 的各种 delegate 方法吧:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{

    NSLog(@"Picker returned successfully");

    NSString *mediaType = [infoobjectForKey:UIImagePickerControllerMediaType];

    if ([mediaType isEqualToString:(__bridge NSString *)kUTTypeMovie]) {

        self.videoURLToEdit = [infoobjectForKey:UIImagePickerControllerMediaURL];

    }

    [picker dismissViewControllerAnimated:YEScompletion:nil];

}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{

    NSLog(@"Picker was cancelled");

    self.videoURLToEdit =nil;

    [picker dismissViewControllerAnimated:YEScompletion:nil];

}

//当用户选择好视频之后,我们就可以显示 video editor:

- (void)viewDidAppear:(BOOL)animated{

    [super viewDidAppear:animated];

    NSString *videoPath = [self.videoURLToEditpath];

    if ([UIVideoEditorControllercanEditVideoAtPath:videoPath]) {

        UIVideoEditorController *videoEditor = [[UIVideoEditorControlleralloc]init];

        videoEditor.delegate = self;

        videoEditor.videoPath = videoPath;

        [selfpresentViewController:videoEditor animated:YEScompletion:nil];

        self.videoURLToEdit =nil;

    }else{

        NSLog(@"Cannot edit the video at this path");

    }

}


在上面的示例中,用户可以从媒体库中选择任意的一个 video。选择之后,我们将通过
0 0
原创粉丝点击