iOS:<Photos/Photos.h>获取相册视频以及图片

10 篇文章 0 订阅

转自:http://www.jianshu.com/p/ea0274a33209


因为项目的需求,要捕获相册中的视频与图片,之前也对之尚未做过什么探讨,仅知道iOS8.0后,苹果推出了新的相册管理的包,那么正好,现在可以看看这个框架了,也知道AlAssetLibrary,使用的话倒是没有详细应用过,因此也不与PhotoKit进行对比了。
先放个git:https://github.com/wizetLee/TestPhotoKit



类的介绍:

//PHAsset 用户照片库中一个单独的资源,简单而言就是单张图片的元数据吧
//PHAsset 组合而成PHAssetCollection(PHCollection)一个单独的资源集合(PHAssetCollection)可以是照片库中相簿中一个相册或者照片中一个时刻,或者是一个特殊的“智能相册”。这种智能相册包括所有的视频集合,最近添加的项目,用户收藏,所有连拍照片等
//PHCollectionList 则是包含PHCollection的PHCollection。因为它本身就是PHCollection,所以集合列表可以包含其他集合列表,它们允许复杂的集合继承。例子:年度->精选->时刻
//PHFetchResult 某个系列(PHAssetCollection)或者是相册(PHAsset)的的返回结果,一个集合类型,PHAsset或者PHAssetCollection的类方法均可以获取到
//PHImageManager 处理图片加载,加载图片过程有缓存处理
//PHCachingImageManager(PHImageManager的抽象) 处理图像的整个加载过程的缓存要加载大量资源的缩略图时可以使用该类的startCachingImage...预先将图像加载到内存中 ,使用时注意size要一致
//PHImageRequestOptions设置加载图片方式的参数()
//PHFetchOptions集合资源的配置方式(按一定的(例如时间)顺序对资源进行排列、隐藏/显示某一个部分的资源集合)


先挑明自己踩到的坑..

 /*
     1、 首次加载APP时出现的问题:仅会获取相应的权限 而不会响应方法
     */
    //每次访问相册都会调用这个handler  检查改app的授权情况
    //PHPhotoLibrary 
    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
        if (status == PHAuthorizationStatusAuthorized) {
          //code
        }
    }];

    /*
     2、获取所有图片(注意不能在胶卷中获取图片,因为胶卷中的图片包含了video的显示图)
     */
    [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];//这样获取

    /*
     3、使用PHImageManager请求时的回调同步or异步时、block回调次数的问题
     */

    /*
     4、回调得出的图片size的问题: 由3个参数决定
     */
    /*
     在ShowAlbumViewController 中观察

     在PHImageContentModeAspectFill 下  图片size 有一个分水岭  {125,125}   {126,126}
     当imageOptions.resizeMode = PHImageRequestOptionsResizeModeExact;
     时: 设置size 小于{125,125}时,你得到的图片size 将会是设置的1/2

     而在PHImageContentModeAspectFit 分水岭  {120,120}   {121,121}
     */
    /*
     5、回调中info字典key消失的问题: 当最终获取到的图片的size的高/宽没有一个能达到原有的图片size的高/宽时 部分key 会消失
     */

一、先来一个简单的练习吧:获取本机系统所有的图片

在collectionView中

- (void)getAllPhotosFromAlbum {//配置简单 ,但是参数却是比价多且
    self.options= [[PHImageRequestOptions alloc] init];//请求选项设置
    self.options.resizeMode=PHImageRequestOptionsResizeModeExact;
//resizeMode  自定义设置图片的大小 枚举类型*
// PHImageRequestOptionsResizeMode:*
//PHImageRequestOptionsResizeModeNone = 0, //保持原size
//PHImageRequestOptionsResizeModeFast, //高效、但不保证图片的size为自定义size
//PHImageRequestOptionsResizeModeExact, //严格按照自定义size

   self.options.synchronous=YES;   //YES 一定是同步    NO不一定是异步
  imageOptions.resizeMode = PHImageRequestOptionsResizeModeExact;
        /*
     PHImageRequestOptionsResizeModeNone // 不调整大小
     PHImageRequestOptionsResizeModeFast // 由系统去安排,情况不定:有时你设置的size比较低,会根据你设的size,有时又会比
     PHImageRequestOptionsResizeModeExact// 保证精确到自定义size :此处精确的前提得用PHImageContentModeAspectFill
     */

    //simageOptions.version = PHImageRequestOptionsVersionCurrent;//版本 iOS8.0之后出的图片编辑extension,可以根据次枚举获取原图或者是经编辑过的图片,
    /*PHImageRequestOptionsVersion:
     PHImageRequestOptionsVersionCurrent = 0, //当前的(编辑过?经过编辑的图:原图)
     PHImageRequestOptionsVersionUnadjusted, //经过编辑的图
     PHImageRequestOptionsVersionOriginal    //原始图片
     */

    //    imageOptions.networkAccessAllowed = YES;//用于开启iClould中下载图片
    //    imageOptions.progressHandler   //iClould下载进度的回调

    imageOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;//在imageOptions.synchronous = NO的情况下最终决定是否是异步

//容器类
  (PHFetchResult *) self.assets= [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];
    //此处option是对获取得到对 Collection 的配置  我只是把它设为nil了 可以这样使用
   /*
//例如按资源的创建时间进行一个排序
         PHFetchOptions *options = [[PHFetchOptions alloc] init];
//    NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:nil ascending:YES];
         options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]]; 
//其中:key是PHAsset类的属性   这是一个kvc
         PHFetchResult *assetsFetchResults = [PHAsset fetchAssetsWithOptions:options];
    */
  [self.containView.collectionView reloadData];
}

- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(NSIndexPath*)indexPath {
    AlbumCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ALBUMCELLID forIndexPath:indexPath];
//cell.backgroundColor= [UIColor redColor];
    CGSize size =CGSizeMake(50,50);//自定义image size变化情况颇为复杂 下面由说到

    //返回一个 PHImageRequestID,在异步请求时可以根据这个ID去取消请求,同步就没办法了..
    [[PHImageManager defaultManager] requestImageForAsset:self.assets[indexPath.row] targetSize:size contentMode:PHImageContentModeDefault options:self.options resultHandler:^(UIImage*_Nullable result,NSDictionary*_Nullable info) {
 /*
         最终产生图片的size是有   imageOptions.resizeMode(即PHImageRequestOptions) 以及 PHImageContentMode  决定的,当然也有我们设定的size
         优先级而言 
         PHImageRequestOptions > PHImageContentMode
         */
        //这个handler 并非在主线程上执行,所以如果有UI的更新操作就得手动添加到主线程中
//       dispatch_async(dispatch_get_main_queue(), ^{ //update UI  });

#pragma If -[PHImageRequestOptions isSynchronous] returns NO (or options is nil), resultHandler may be called 1 or more times. .........异步就这个回调会调用1或多次....
#pragma If -[PHImageRequestOptions isSynchronous] returns YES, resultHandler will be called exactly once同步就1次.
//一开始本来打算是利用数据吧所有的相片先存起来的.但是发现同步会卡UI  但是异步又会被回调多次,我的数组都变成double了...只好把任务方法方法cellforItem中
    cell.photoImageView.contentMode = UIViewContentModeScaleAspectFit;
    cell.photoImageView.image = result;
}];
  return cell;
}
/*注意这个info字典   有时这个info甚至为null   慎用
     里面的key是比较奇怪的
     尽量不要用里面的key
     因为这个key 会变动: 当我们最终获取到的图片的size的高/宽  没有一个达到能原有的图片size的高/宽时
     部分key 会消失  如 PHImageFileSandboxExtensionTokenKey , PHImageFileURLKey
     */

    /*
     在PHImageContentModeAspectFill 下  图片size 有一个分水岭  {125,125}   {126,126}
     当imageOptions.resizeMode = PHImageRequestOptionsResizeModeExact;
     时: 设置size 小于{125,125}时,你得到的图片size 将会是设置的1/2

     而在PHImageContentModeAspectFit 分水岭  {120,120}   {121,121}   
     至于为什么会这样???我不知道 - -   可能苹果考虑性能吧...谁知道告诉下啊
     */

注意到上面这个resultHandler,返回一个UIImage,以及一个NSDictionary,图片就不多说了,关键是这个info实在是诡异...

这就引起了我的关注:size和key的关系

围绕着size的大小这个key竟然是不一样的............
我把图也打印出来了// 条件: size = {300,300}


本来是猜测我们设定的这个size比原图小的时候,会产生一张新的图片,而这张图片本地资源是不存在的,所以少了部分的key,

但是现在就尴尬了,看第二个image的原图,分明也是比{300,300}小的,为什么也没了部分key了呢,不太懂....

大家不要误会,第一张图片的原图是肯定大于{300,300} 的,为什么显示不是{300,300},因为我使用处理图片的模式为PHImageContentModeAspectFit,所以显示下来的并非我们{300,300}而是保留原图的比例,大家可以动手去试一试

而且这个size其实是像素:
CGSizeMake(self.assets[indexPath.row].pixelWidth,self.assets[indexPath.row].pixelHeight);
或者设定一个肯定比原图大的size就能获取到原图了....当然,后者是不靠谱的...

或许是这个size出的问题吧,会导致如果我要根据这个PHimageFileKey 获取本地的图片的时候就因为某部分的image因为size的原因缺少这个key使得找不到这张图,使得我app出现bug....不过这个方法真的挺不安全的,建议是把返回的result 那张image 写进tmp里面 再使用吧。。。。

再者就是异步请求次数跟size的关系

当我的self.options.synchronous=NO;//就是一个异步请求的过程(后来发现其实异步请求并不由options的synchronous属性决定)
而这个PHImageRequestOptions 可以根据它的一个属性deliveryMode 去控制异步请求的次数
PHImageRequestOptionsDeliveryMode:
PHImageRequestOptionsDeliveryModeOpportunistic//根据我self.options.synchronous判断返回结果是一个抑或多个
PHImageRequestOptionsDeliveryModeHighQualityFormat //制定的同步返回一个结果,返回的图片质量是比我们设定的size会好一点(实际上与PHImageRequestOptions的resizeMode枚举相关)
PHImageRequestOptionsDeliveryModeFastFormat//仅返回一次,效率较高之余获得的图质量不太好

 我这边配合的resizeMode模式为强制自定义的图片大小,即:
self.options.resizeMode=PHImageRequestOptionsResizeModeExact;//严格按照自定义图片大小的加载模式

如果不是这个枚举的话,返回的PHImageRequestOptionsDeliveryModeOpportunistic第一次返回的缩略图,以及PHImageRequestOptionsDeliveryModeFastFormat所返回的缩略图最小默认是{6060},
PHImageRequestOptionsResizeModeExact则可以随意设置

值得注意的是,当我们选择的是PHImageRequestOptionsDeliveryModeOpportunistic时,返回的次数是跟size有关系的,你设定的的size 太小的话仅会回调一次,大的话,首次返回的是一个小的缩略图(这个缩略图最大是{60,60},具体值根据比例),二次回调才会得到我们想要的图片

总而言之,图片的真实size跟resizeMode和PHImageRequestOptionsDeliveryMode以及我们设定的size都有关联吧,具体应用的时候就要多试试几次,观察自己真实所需吧...

接下来的是我要找的是视频......问题又出现了,这个PhotoKit有提供查找视频的方式么...
然后我把这修改了一下。。。改成了找Video 的元数据   哈哈哈哈哈哈哈
self.assets= [PHAsset fetchAssetsWithMediaType:**PHAssetMediaTypeVideo** options:nil];

但我好像又踩上了自己挖的坑了...



全是图片....不,不是这样的。。。

在回头看看发现有PHImageManager 这个单例提供我们3个方法去找得到Vide 我则选取了其中一个通用的方法

PHFetchResult *assetsResult = [PHAssetfetch AssetsWithMediaType:PHAssetMediaType Videooptions:nil];
PHVideoRequestOptions *options2 = [[PHVideoRequestOptions alloc] init];
options2.deliveryMode=PHVideoRequestOptionsDeliveryModeAutomatic;
for(PHAsset *a in assetsResult) {                       
   [[PHImageManager defaultManager] requestAVAssetForVideo:a options:options2 resultHandler:^(AVAsset*_Nullable asset,
    AVAudioMix*_Nullable audioMix,NSDictionary*_Nullable info) {
    NSLog(@"%@",info);
  }];
}

找到你了....

不过你居然在。。。PHImageFileSandboxExtensionTokenKey。。。这个key里面



看来地址是要用要用截取的了,可以直接输入到finder就能找到这个视频,但是前面的字符串就得让我们手动去取其子字符串只需要拿到video的Path就可以了

很不安全,我真的怕这个key突然又因为什么原因而miss掉了........
然后我看了看asset 的类型 发现它的类型为AVURLAsset,有点意思,看看里面发现了一个是有个URL属性的!而且是asset的绝对路径,简直完美...

//video路径获取
if (asset && [asset isKindOfClass:[AVURLAsset class]] && [NSString stringWithFormat:@"%@",((AVURLAsset *)asset).URL].length > 0) {
  NSString *videoURLStr = [NSString stringWithFormat:@"%@",((AVURLAsset *)asset).URL];
  videoPath = [videoURLStr substringWithRange:NSMakeRange([videoURLStr rangeOfString:@"/"].location, videoURLStr.length -[videoURLStr rangeOfString:@"/"].location)];
}//这个截取字符串的操作柑橘的多余的

二、根据实际需求的部分获取资源

怎么个实际法呢,有时候你对着一大堆图片,然后找啊找,调啊调,还真的不是什么好方法...为什么就不能在我分好的类别中选取呢!!!!

好的,就下来就说这种情况,大家在开头都一定看到那幅,资源与资源集合的一个关系图...

获取所有用户自定义的相册:1\2\3分别是我创建的相册,以下代码能捕获到,自己创建的的相册的内容


捕获系统相册中的图片/video




collection cell 没处理,不过效果还是显而易见的,同个一个tableView 去选取自己想要找的部分即可
中间那七张相同的图片其实是我放入系统中的七个相同视频的图片...

解释一下

PHFetchResult*smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];

这个获取资源集合的方法 需要填写两个枚举的类型,大概翻译了下,有错误的大家可以提一下,我会非常感激的


参考文章:
http://objccn.io/issue-21-4/#PhotoKit-Object-Model
http://kayosite.com/ios-development-and-detail-of-photo-framework-part-two.html



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值