iOS中读取照片库及保存图片或视频到照片库的要点解析
读取照片库PhotoLibrary
iOS中如果我们只有一次读取一张图片或者一个视频(或拍一张照片/视频)的需求,那么我们用UIImagePickerController就可以搞定。但是很多时候我们需要一次性从PhotoLibrary读取多个照片或者视频,这时候我们就需要另辟蹊径了,好在apple为我们提供了相应的接口。
在开始coding之前我们想要认识几个类:
ALAssetsLibrary:代表整个PhotoLibrary,我们可以生成一个它的实例对象,这个实例对象就相当于是照片库的句柄。
ALAssetsGroup:照片库的分组,我们可以通过ALAssetsLibrary的实例获取所有的分组的句柄。
ALAsset:一个ALAsset的实例代表一个资产,也就是一个photo或者video,我们可以通过他的实例获取对应的subnail或者原图等等。
还需要了解的一个东东就是blocks,apple在iOS4.0以后大量出现了这玩意儿,有使用越来越广的意思,不过这玩意儿确实好用。关于这玩意儿的内容我在这里不多讲,关注我的博客我会细讲。
对于本文的需求,我们读取group和每个asset都是异步的,但是我们现在用blocks我们可以在一个函数里面搞定。所以blocks确实很方便。
下面直接看代码吧:
ALAssetsLibrary*assetsLibrary=[[ALAssetsLibraryalloc]init];//生成整个photolibrary句柄的实例 NSMutableArray*mediaArray=[[NSMutableArrayalloc]init];//存放media的数组 [assetsLibraryenumerateGroupsWithTypes:ALAssetsGroupAllusingBlock:^(ALAssetsGroup*group,BOOL*stop){//获取所有group [groupenumerateAssetsUsingBlock:^(ALAsset*result,NSUIntegerindex,BOOL*stop){//从group里面 NSString*assetType=[resultvalueForProperty:ALAssetPropertyType]; if([assetTypeisEqualToString:ALAssetTypePhoto]){ NSLog(@"Photo"); }elseif([assetTypeisEqualToString:ALAssetTypeVideo]){ NSLog(@"Video"); }elseif([assetTypeisEqualToString:ALAssetTypeUnknown]){ NSLog(@"UnknowAssetType"); } NSDictionary*assetUrls=[resultvalueForProperty:ALAssetPropertyURLs]; NSUIntegerassetCounter=0; for(NSString*assetURLKeyinassetUrls){ NSLog(@"AssetURL%lu=%@",(unsignedlong)assetCounter,[assetUrlsobjectForKey:assetURLKey]); } NSLog(@"RepresentationSize=%lld",[[resultdefaultRepresentation]size]); }]; }failureBlock:^(NSError*error){ NSLog(@"Enumeratetheassetgroupsfailed."); }];
保存图片或视频到PhotoLibrary
时文件然后,然后通过临时文件的路径去转存到photolibrary。
我们直接来看相应的API:
//Thesemethodscanbeusedtoaddphotosorvideostothesavedphotosalbum. //WithaUIImage,theAPIusercanuse-[UIImageCGImage]togetaCGImageRef,andcast-[UIImageimageOrientation]toALAssetOrientation. -(void)writeImageToSavedPhotosAlbum:(CGImageRef)imageReforientation:(ALAssetOrientation)orientationcompletionBlock:(ALAssetsLibraryWriteImageCompletionBlock)completionBlock; //TheAPIuserwillhavetospecifytheorientationkeyinthemetadatadictionarytopreservetheorientationoftheimage -(void)writeImageToSavedPhotosAlbum:(CGImageRef)imageRefmetadata:(NSDictionary*)metadatacompletionBlock:(ALAssetsLibraryWriteImageCompletionBlock)completionBlock__OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_1); //Ifthereisaconflictbetweenthemetadataintheimagedataandthemetadatadictionary,theimagedatametadatavalueswillbeoverwritten -(void)writeImageDataToSavedPhotosAlbum:(NSData*)imageDatametadata:(NSDictionary*)metadatacompletionBlock:(ALAssetsLibraryWriteImageCompletionBlock)completionBlock__OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_1); -(void)writeVideoAtPathToSavedPhotosAlbum:(NSURL*)videoPathURLcompletionBlock:(ALAssetsLibraryWriteVideoCompletionBlock)completionBlock;
前三个都是存图片的,通过参数我们可以发现,第一个使用了我们传进去的方向,第二个可以通过传入image的metadata保留image的metadata,前两个都是把图片转成CGImageRef再保存,第三个是传入NSData所以可以完整保留image的信息,同时也有metadata传进去,如果image自带的信息与metadata冲突那metadata会覆盖图片本身所带的metadata。
最后一个是存储视频的API,可以看到参数是一个NSURL,这个只要穿一个本地临时文件的fileURL就好了。
存储图片根据你的需求选择适当的API,比如我们获取到的是UIImage的实例,那么我们用第一个或者第二个比较方便,如果我们从本地临时文件读取image的数据那么我们直接用第三个就比较方便。
下面来一段简单的代码:
-(void)saveImage:(UIImage*)image{ ALAssetsLibrary*assetsLibrary=[[ALAssetsLibraryalloc]init]; [assetsLibrarywriteImageToSavedPhotosAlbum:[imageCGImage]orientation:(ALAssetOrientation)image.imageOrientationcompletionBlock:^(NSURL*assetURL,NSError*error){ if(error){ NSLog(@"Saveimagefail:%@",error); }else{ NSLog(@"Saveimagesucceed."); } }]; }
保存video就麻烦点了,你需要先把video写入本地文件然后,获取到本地临时文件的路径,然后调用上面的第四个API写入photolibrary。
关于写入临时文件,我之前写过一篇关于文件读写的文章,可以去看看。
我这里奉上一个把工程资源库的video写入photolibrary的demo,这样你就可以把video导入模拟器了,方便有些时候测试。
主要代码如下:
-(void)save:(NSString*)urlString{ ALAssetsLibrary*library=[[ALAssetsLibraryalloc]init]; [librarywriteVideoAtPathToSavedPhotosAlbum:[NSURLfileURLWithPath:urlString] completionBlock:^(NSURL*assetURL,NSError*error){ if(error){ NSLog(@"Savevideofail:%@",error); }else{ NSLog(@"Savevideosucceed."); } }]; }