Photokit 仿微信实现多图选择(上)

git地址: https://github.com/wangjinshan/IJSPhotoSDK
集成文档已经在git更新了 支持cocoapods

项目演示

demo.gif
001.PNG
002.PNG
003.PNG
004.PNG
005.PNG
006.PNG
007.PNG
008.PNG
009.PNG

具体的demo 后面会更新到github上

Photokit介绍

这篇主要介绍如何通过 Photokit获取数据

photokit.jpg

1,基类 PHObject

Photos 框架中的根类PHObject只有一个公开接口 localIdentifier,是对象唯一标志符.PHObject实现了-isEqual 和-hash方法.可以直接使用localIdentifier属性对PHObject及其子类对象进行对比是否同一个对象

2,数据类型

PHAsset 、PHAssetCollection、PHCollectionList 是Photos框架中的模型类

PHAsset :代表系统的一个图片,视频或者Live Photo
PHAssetCollection:是一组有序的资源集合,包括相册、moments、智能相册以及共享照片流.比如:系统相册里的时刻一个分类,用户创建的相册或者智能相册
PHCollectionList : 相册集合, 比如:时刻里的年或者包含用户创建的一个或者多个相册
表示一组PHCollection,而它本身也是一个PHCollection,因此PHCollection作为一个集合,可以包含其他集合
如下资源结构图:


jiegou.png
2.1 PHAsset.h
2.1.1 PHAsset

代表系统的一个图片,视频或者Live Photo
属性介绍:

[1] mediaType :资源类型,图片或者音频或视频
 PHAssetMediaTypeUnknown = 0,
 PHAssetMediaTypeImage   = 1,
 PHAssetMediaTypeVideo   = 2,
 PHAssetMediaTypeAudio   = 3,
 
 [2] mediaSubtypes
 图片又包含全景图(Panorama)、HDR图片、屏幕截图、livePhoto .live photo 加3Dtouch效果 我们可以使用照片资源的 mediaSubtypes 属性验证资源库中的图像在捕捉时是否开启了 HDR,拍摄时是否使用了相机应用的全景模式
 
 PHAssetMediaSubtypeNone      = 0,
 
 // Photo subtypes
 PHAssetMediaSubtypePhotoPanorama
 PHAssetMediaSubtypePhotoHDR
 PHAssetMediaSubtypePhotoScreenshot
 PHAssetMediaSubtypePhotoLive
 PHAssetMediaSubtypePhotoDepthEffect
 
 // Video subtypes
 PHAssetMediaSubtypeVideoStreamed      = (1UL << 16),
 PHAssetMediaSubtypeVideoHighFrameRate = (1UL << 17),
 PHAssetMediaSubtypeVideoTimelapse
 
 [3] pixelWidth 像素宽度 pixelHeight 高度
 
 [4] creationDate 创建时间   modificationDate 修改时间  location 位置信息 duration时长
 
 [5] hidden 要验证一个资源是否被用户标记为收被隐藏,只要检查 PHAsset 实例的 hidden 属性即可。
 [6] Favorite  布尔值,用户是否标记资源为"收藏",我们平时浏览照片或视频,在下方点💗就表示收藏这张图
 
 [7] representsBurst 和 burstSelectionTypes: 对于一个资源,如果其 PHAsset 的 representsBurst 属性为 true,则表示这个资源是一系列连拍照片中的代表照片 (多张照片是在用户按住快门时拍摄的)。它还有一个属性是 burstIdentifier,如果想要获取连拍照片中的剩余的其他照片,可以通过将这个值传入 fetchAssetsWithBurstIdentifier(...) 方法来获取。用户可以在连拍的照片中做标记;此外,系统也会自动用各种试探来标记用户可能会选择的潜在代表照片。这个元数据是可以通过 PHAsset 的 burstSelectionTypes 属性来访问。这个属性是用三个常量组成的位掩码:.UserPick 表示用户手动标记的资源,.AutoPick 表示用户可能标记的潜在资源,.None 表示没有标记的资源
 
 [8] localIdentifier Photos 框架中的根类PHObject只有一个公开接口localIdentifier,是对象唯一唯一标志符.PHObject实现了-isEqual 和-hash方法.可以直接使用localIdentifier属性对PHObject及其子类对象进行对比是否同一个对象
 
 方法
 // 可执行编辑操作
 - (BOOL)canPerformEditOperation:(PHAssetEditOperation)editOperation;
常见的获取资源的方法
// 获取所有的资源  options是获取资源的条件下文介绍
+ (PHFetchResult<PHAsset *> *)fetchAssetsWithOptions:(nullable PHFetchOptions *)options;  
// 从相册中获取资源 , assetCollection 可以传入相册的对象
 + (PHFetchResult<PHAsset *> *)fetchAssetsInAssetCollection:(PHAssetCollection *)assetCollection options:(nullable PHFetchOptions *)options; 
2.2 PHCollection.h
2.2.1, PHCollection :一个抽象类,是PHAssetCollection和PHColletionList的父类

属性:

[1.1]  localizedTitle 相册的标题
// 获取资源的方法
+ (PHFetchResult<PHCollection *> *)fetchCollectionsInCollectionList:(PHCollectionList *)collectionList options:(nullable PHFetchOptions *)options;
2.2.2 , PHAssetCollection 相册(PHAsset集合)

PHAssetCollection是一组有序的资源集合,包括相册、moments、智能相册以及共享照片流.比如:系统相册里的时刻一个分类,用户创建的相册或者智能相册
属性:

[2.1] assetCollectionType  指定资源集合类型来源,比如相册或者“时刻”相册
 PHAssetCollectionTypeAlbum      = 1,      // 用户相册
 PHAssetCollectionTypeSmartAlbum = 2,  // 智能相册
 PHAssetCollectionTypeMoment     = 3,     // 时刻”相册
 
 [2.2] assetCollectionSubtype 子类型
 enum PHAssetCollectionType : Int {
 case Album             //从 iTunes 同步来的相册,以及用户在 Photos 中自己建立的相册
 case SmartAlbum    //经由相机得来的相册
 case Moment            //Photos 为我们自动生成的时间分组的相册
 }
 
 enum PHAssetCollectionSubtype : Int
 {
 PHAssetCollectionSubtypeSmartAlbumSlomoVideos
 PHAssetCollectionSubtypeSmartAlbumSelfPortraits
 PHAssetCollectionSubtypeSmartAlbumScreenshots
 PHAssetCollectionSubtypeSmartAlbumDepthEffect
 PHAssetCollectionSubtypeSmartAlbumLivePhotos
 // Used for fetching, if you don't care about the exact subtype
 PHAssetCollectionSubtypeAny = NSIntegerMax
 
 case PHAssetCollectionSubtypeAlbumRegular              //用户在 Photos 中创建的相册
 case PHAssetCollectionSubtypeAlbumSyncedEvent      //使用 iTunes 从 Photos 照片库或者 iPhoto 照片库同步过来的事件。然而,在iTunes 12 以及iOS 9.0 beta4上,选用该类型没法获取同步的事件相册,而必须使用AlbumSyncedAlbum。
 case PHAssetCollectionSubtypeAlbumSyncedFaces      //使用 iTunes 从 Photos 照片库或者 iPhoto 照片库同步的人物相册。
 case PHAssetCollectionSubtypeAlbumSyncedAlbum          //从iPhoto同步到设备的相册
 case PHAssetCollectionSubtypeAlbumImported                 //从相机或是外部存储导入的相册,完全没有这方面的使用经验,没法验证。
 
 case PHAssetCollectionSubtypeAlbumMyPhotoStream    //用户的 iCloud 照片流
 case PHAssetCollectionSubtypeAlbumCloudShared          //用户使用 iCloud 共享的相册
 case PHAssetCollectionSubtypeSmartAlbumGeneric        //文档解释为非特殊类型的相册,主要包括从 iPhoto 同步过来的相册。
 case PHAssetCollectionSubtypeSmartAlbumPanoramas   //相机拍摄的全景照片
 case PHAssetCollectionSubtypeSmartAlbumVideos          //相机拍摄的视频
 case PHAssetCollectionSubtypeSmartAlbumFavorites       //收藏文件夹
 case PHAssetCollectionSubtypeSmartAlbumTimelapses      //延时视频文件夹,同时也会出现在视频文件夹中
 case PHAssetCollectionSubtypeSmartAlbumAllHidden       //包含隐藏照片或视频的文件夹
 case PHAssetCollectionSubtypeSmartAlbumRecentlyAdded //相机近期拍摄的照片或视频
 case PHAssetCollectionSubtypeSmartAlbumBursts                  //连拍模式拍摄的照片
 case PHAssetCollectionSubtypeSmartAlbumUserLibrary  //这个命名最神奇了,就是相机相册,所有相机拍摄的照片或视频都会出现在该相册中,而且使用其他应用保存的照片也会出现在这里,用户创建出来的
 case Any //包含所有类型
 }
 
 [2.3] startDate endDate 开始 结束时间
 
 [2.4] estimatedAssetCount :估算的asset数量,不精确
 
 [2.5] CLLocation *approximateLocation;  大概的位置
 [2.6] NSArray<NSString *> *localizedLocationNames; 位置地区的名字数组

2.2.3 , PHCollectionList : 相册集合

表示一组PHCollection,而它本身也是一个PHCollection,因此PHCollection作为一个集合,可以包含其他集合
属性:

 [3.1] collectionListType
 [3.2] collectionListSubtype
 [3.3] startDate
 [3.4 ] endDate

获取模型数据
PHAsset 、PHCollection、PHCollectionList有一系列类方法可供我们访问资源的元数据

 1, 比如PHAsset提供了一系列获取PHAsset对象的方法
 + fetchAssetsInAssetCollection:options:
 + fetchAssetsWithMediaType:options:
 + fetchAssetsWithLocalIdentifiers:options:
 + fetchKeyAssetsInAssetCollection:options:
 + fetchAssetsWithOptions:
 + fetchAssetsWithBurstIdentifier:options:
 + fetchAssetsWithALAssetURLs:options:
 其中fetchAssetsInAssetCollection:options:方法可以获取资源集合中的所有asset对象。每个方法中的 PHFetchOptions参数,是获取asset对象的一些配置,我们可以设置获取asset的条件,比如获取哪种资源,如何分类。获取的时候,如果该参数为空,则使用系统的默认值,当我们调用如上所示方法获取时,可以直接传nil
 

3, 搜索的条件

3.1 PHFetchOptions.h

PHFetchOptions : option的集合,对asset对象进行 过滤,排序和管理
属性:

 [1] predicate 做选择的约束条件。比如,只获取图片,不获取视频。指定 PHAssetMediaType为image.
 
 [2]  sortDescriptors 可指定字段用来对获取结果进行排序
 
 [3] includeHiddenAssets 获取结果是否包括被隐藏的资源
 
 [4] includeAllBurstAssets 获取结果是否包括连拍资源
 
 [5] includeAssetSourceTypes 资源的来源
 PHAssetSourceTypeNone
 PHAssetSourceTypeUserLibrary
 PHAssetSourceTypeCloudShared
 PHAssetSourceTypeiTunesSynced
 
 [6] fetchLimit  搜索结果的限制 ,0 表示无限制
 
 [7] wantsIncrementalChangeDetails ,搜索结果细节变化

4, 搜索的结果 PHFetchResult

PHFetchResult.h
PHFetchResult: 类似数组,包含assets或者collections有序的一系列集合

特点: 同步快速获取结果,
即使结果集很大,框架也能保证获取速度. 因为它不会一次性将所有结果放进内存,而是按需批量加载
可以用类似 NSArray 的接口来访问PHFetchResult结果内的集合
提供快速枚举的方法

  • (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(ObjectType obj, NSUInteger idx, BOOL *stop))block;
    就算满足请求的照片库内容发生了改变,获取方法所返回的 PHFetchResult 对象是不会自动更新。在后面的小节中,我们会介绍如何对返回的 PHFetchResult 对象的改变进行观察并处理更新内容。
    可以借助 PHObjectChangeDetails 或 PHFetchResultChangeDetails 对象来观察这些变化

综合例子如下:

// 获取相机胶卷的相册得到PHAsset对象放到IJSAlbumModel中
-(void)getCameraRollAlbumContentImage:(BOOL)contentImage contentVideo:(BOOL)contentVideo  completion:(void (^)(IJSAlbumModel *model))completion
{
    __block IJSAlbumModel *model;
    if (iOS8Later)
    {
        PHFetchOptions *option = [[PHFetchOptions alloc] init];
        if (!contentVideo) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage];
        if (!contentImage) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld",
                                                    PHAssetMediaTypeVideo];
        if (!self.sortAscendingByModificationDate)
        {
            option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:self.sortAscendingByModificationDate]];
        }
        PHFetchResult<PHAssetCollection *>  *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
        
        for (PHAssetCollection *collection in smartAlbums)
        {
            if (![collection isKindOfClass:[PHAssetCollection class]]) continue; // 有可能是PHCollectionList类的的对象,过滤掉
            if ([self isCameraRollAlbum:collection.localizedTitle])
            {
                PHFetchResult<PHAsset *>  *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:option];
                model = [self modelWithResult:fetchResult name:collection.localizedTitle];
                if (completion) completion(model);
                break;
            }
        }
    }
    else
    {
        [self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
            if ([group numberOfAssets] < 1) return;
            NSString *name = [group valueForProperty:ALAssetsGroupPropertyName];
            if ([self isCameraRollAlbum:name])
            {
                model = [self modelWithResult:group name:name];
                if (completion) completion(model);
                *stop = YES;
            }
        } failureBlock:nil];
    }
}

至此我们已经成功的获取了 asset 对象



接下来我们将我们获取的 PHAsset对象解析成我们需要 UIImage 对象
需要的类介绍:

5, 解析PHAsset

PHImageManager.h

5.1 PHImageManager

在框架中是个单例对象,用[PHImageManager defaultManager]获取,它提供了加载图片和视频的方法,解析 PHAsset 资源
方法介绍:

// 获取自定义大小的图片
- (PHImageRequestID)requestImageForAsset:(PHAsset *)asset targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode options:(nullable PHImageRequestOptions *)options resultHandler:(void (^)(UIImage *__nullable result, NSDictionary *__nullable info))resultHandler;
官方注释翻译:
 如果获取的资源的宽高比不符合, contentMode 决定现实的大小
 PHImageContentModeAspectFit:  等比例适应
 PHImageContentModeAspectFill:  等比例缩放适应
 PHImageContentModeDefault = PHImageContentModeAspectFit  默认值
 [PHImageRequestOptions isSynchronous] returns NO (or options is nil), resultHandler 可能会请求多次
 deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic
 默认情况下,这些API是异步执行,但是我们可以通过options参数中的synchronous属性,设置为同步执行,这些方法会阻塞当前调用线程直到下载完成或者发生错误
 请求取消将不再返回 resultHandler

方法参数解读:
 asset:   需要解析的资源
 targetSize: 需要获取的图像的尺寸,如果输入的尺寸大于资源原图的尺寸,则只返回原图。需要注意在 PHImageManager 中,所有的尺寸都是用 Pixel 作为单位(Note that all sizes are in pixels),因此这里想要获得正确大小的图像,需要把输入的尺寸转换为 Pixel。如果需要返回原图尺寸,可以传入 PhotoKit 中预先定义好的常量?PHImageManagerMaximumSize,表示返回可选范围内的最大的尺寸,即原图尺寸
 contentMode: 图像的剪裁方式,控制照片应该以按比例缩放还是按比例填充的方式放到最终展示的容器内。注意如果 targetSize 传入PHImageManagerMaximumSize,则 contentMode 无论传入什么值都会被视为 PHImageContentModeDefault
 options: PHImageRequestOptions 的实例,可以控制的内容相当丰富,包括图像的质量、版本,也会有参数控制图像的剪裁
 resultHandler: 请求结束后被调用的 block,返回一个包含资源对于图像的 UIImage 和包含图像信息的一个 NSDictionary,在整个请求的周期中,这个 block 可能会被多次调用

// 获取原图数据
请求大图 ,回调只执行一次,deliveryMode直接被忽略,设置了PHImageRequestOptionsVersionCurrent 并且资源被调整过,则返回最大的图
- (PHImageRequestID)requestImageDataForAsset:(PHAsset *)asset options:(nullable PHImageRequestOptions *)options resultHandler:(void(^)(NSData *__nullable imageData, NSString *__nullable dataUTI, UIImageOrientation orientation, NSDictionary *__nullable info))resultHandler;
// 取消正在加载的数据线
- (void)cancelImageRequest:(PHImageRequestID)requestID;
5.2 获取图片资源的控制条件类 PHImageRequestOptions

PHImageRequestOptions中包含了一系列控制请求图像的属性
如果resizeMode所控制的剪裁结果有所冲突,PhotoKit 会以 resizeMode 的结果为准
属性详解:

1,  PHImageRequestOptionsVersion version:

 这个属性是指获取的图像是否需要包含系统相册“编辑”功能处理过的信息(如滤镜,旋转等)
 图片编辑extension,可以根据次枚举获取原图或者是经编辑过的图片
 PHImageRequestOptionsVersionCurrent = 0, //当前的(编辑过?经过编辑的图:原图)
 PHImageRequestOptionsVersionUnadjusted, //经过编辑的图
 PHImageRequestOptionsVersionOriginal       //原始图片
 
  2, PHImageRequestOptionsDeliveryMode deliveryMode:
 则用于控制请求的图片质量
 PHImageRequestOptionsDeliveryModeOpportunistic:在速度与质量中均衡 根据我options.synchronous判断返回结果是一个或多个
 PHImageRequestOptionsDeliveryModeHighQualityFormat 制定的同步返回一个结果,返回的图片质量是比我们设定的size会好一点(实际上与PHImageRequestOptions的resizeMode枚举相关) 高质量图
 PHImageRequestOptionsDeliveryModeFastFormat 仅返回一次,效率较高之余获得的图质量不太好,速度最快
 
 
  3, PHImageRequestOptionsResizeMode resizeMode:  PHImageRequestOptionsResizeModeNone (or no resize)无效 属性控制图像的剪裁
  
 4 CGRect normalizedCropRect: 用于对原始尺寸的图像进行裁剪,基于比例坐标。只在 resizeMode 为 Exact 时有效
 5 BOOL networkAccessAllowed; 是否允许从 icloud请求资源 另一个和 iCloud 相关的属性是 progressHandler。你可以将它设为一个PHAssetImageProgressHandler 的 block,当从 iCloud 下载照片时,它就会被图像管理器自动调用
 6 BOOL synchronous 是否为同步操作,默认为NO,如果设置为YES则,相关模式下只会返回一张图片
  PHAssetImageProgressHandler progressHandler 当图像需要从 iCloud 下载时,这个 block 会被自动调用,block 中会返回图像下载的进度,图像的信息,出错信息。开发者可以利用这些信息反馈给用户当前图像的下载进度以及状况,但需要注意?progressHandler 不在主线程上执行,因此在其中需要操作 UI,则需要手工放到主线程执行
 上面有提到,requestImageForAsset 中的参数?resultHandler 可能会被多次调用,这种情况就是图像需要从 iCloud 中下载的情况。在?requestImageForAsset 返回的内容中,一开始的那一次请求中会返回一个小尺寸的图像版本,当高清图像还在下载时,开发者可以首先给用户展示这个低清的图像版本,然后 block 在多次调用后,最终会返回高清的原图。至于当前返回的图像是哪个版本的图像,可以通过 block 返回的 NSDictionary info 中获知,PHImageResultIsDegradedKey 表示当前返回的 UIImage 是低清图。如果需要判断是否已经获得高清图,可以这样判断:
 
 BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
 
 requestImageForAsset 发出对图像的请求时,如果在同一个 PHImageManager 中同时对同一个资源发出图像请求,请求的进度是可以共享的,因此我们可以利用这个特性,把 PHImageManager 以单例的形式使用,这样在切换界面时也不用担心无法传递图像的下载进度。例如,在图像的列表页面触发了下载图像,当我们离开列表页面进入预览大图界面时,并不用担心会重新图像会重新下载,只要没有手工取消图像下载,进入预览大图界面下载图像会自动继续从上次的进度下载图像
5.3 livePhoto筛选类 PHLivePhotoRequestOptions
 PHImageRequestOptionsVersion version;
  PHImageRequestOptionsDeliveryMode deliveryMode;
  BOOL networkAccessAllowed;
  PHAssetImageProgressHandler progressHandler;// 网络加载的进度
5.4 video筛选类 PHVideoRequestOptions
BOOL networkAccessAllowed;
PHVideoRequestOptionsVersion version;
 PHVideoRequestOptionsDeliveryMode deliveryMode;
 PHAssetVideoProgressHandler progressHandler;  // 网络进度
 
 // 获取视频
 - (PHImageRequestID)requestPlayerItemForVideo:(PHAsset *)asset options:(nullable PHVideoRequestOptions *)options resultHandler:(void (^)(AVPlayerItem *__nullable playerItem, NSDictionary *__nullable info))resultHandler;
 // 导出视频方法
 - (PHImageRequestID)requestAVAssetForVideo:(PHAsset *)asset options:(nullable PHVideoRequestOptions *)options resultHandler:(void (^)(AVAsset *__nullable asset, AVAudioMix *__nullable audioMix, NSDictionary *__nullable info))resultHandler;
 
5.5 PHPhotoLibrary

PHPhotoLibrary:
系统中PHPhotoLibrary单例对象 是用来维护用户照片库。当我们需要编辑资源对象元数据、资源内容、或者插入新的资源对象等,都可以借助通过PHPhotoLibrary单例对象执行block,block中创建我们指定的请求对象(比如PHAssetChangeRequest,PHAssetCollectionChangeRequest, PHCollectionListChangeRequest的对象)。photoLibraryDidChange(changeInfo: PHChange!)中进行
授权状态

 {
 PHAuthorizationStatusNotDetermined = 0, // 未选择
 PHAuthorizationStatusRestricted,        // 用户受到某些限制,不能自己决定,比如:家长控制
 PHAuthorizationStatusDenied,            // 用户明确拒绝
 PHAuthorizationStatusAuthorized         // 已经授权
 }
 // 协议 :
 PHPhotoLibraryChangeObserver:
 PHPhotoLibraryChangeObserver 协议能让我们知道照片相册库中的改变。Photos会发送系统图片改变的消息,我们可以遵守PHPhotoLibraryChangeObserver协议,并通过 PHPhotoLibrary的registerChangeObserver方法将对象注册为观察者,时时接收照片改变的消息。
 // 串行队列 相册数据改变 知道照片相册库中的改变
 - (void)photoLibraryDidChange:(PHChange *)changeInstance;
 
 // 单利初始化
 + (PHPhotoLibrary *)sharedPhotoLibrary;
 //判断授权
 + (PHAuthorizationStatus)authorizationStatus;
 请求授权
 + (void)requestAuthorization:(void(^)(PHAuthorizationStatus status))handler;

 //  执行同步和异步数据
 - (void)performChanges:(dispatch_block_t)changeBlock completionHandler:(nullable void(^)(BOOL success, NSError *__nullable error))completionHandler;
 - (BOOL)performChangesAndWait:(dispatch_block_t)changeBlock error:(NSError *__autoreleasing *)error;
 
 // 将对象注册为观察者,时时接收照片改变的消息。
 - (void)registerChangeObserver:(id<PHPhotoLibraryChangeObserver>)observer;
 - (void)unregisterChangeObserver:(id<PHPhotoLibraryChangeObserver>)observer;

综合例子

- (PHImageRequestID)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler networkAccessAllowed:(BOOL)networkAccessAllowed
{
    if ([asset isKindOfClass:[PHAsset class]]) {
        CGSize imageSize;
        if (photoWidth < JSScreenWidth && photoWidth < _photoPreviewMaxWidth) {
            imageSize = assetGridThumbnailSize;
        } else {
            PHAsset *phAsset = (PHAsset *)asset;
            CGFloat aspectRatio = phAsset.pixelWidth / (CGFloat)phAsset.pixelHeight;
            CGFloat pixelWidth = photoWidth * JSScreenScale * 1.5;
            // 超宽图片
            if (aspectRatio > 1) {
                pixelWidth = pixelWidth * aspectRatio;
            }
            // 超高图片
            if (aspectRatio < 0.2) {
                pixelWidth = pixelWidth * 0.5;
            }
            CGFloat pixelHeight = pixelWidth / aspectRatio;
            imageSize = CGSizeMake(pixelWidth, pixelHeight);
        }
        
        __block UIImage *image;
        PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init];
        option.resizeMode = PHImageRequestOptionsResizeModeFast;
        int32_t imageRequestID = [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:imageSize contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage *result, NSDictionary *info) {
            if (result) {
                image = result;
            }
            BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
            if (downloadFinined && result) {
                result = [self fixOrientation:result];
                if (completion) completion(result,info,[[info objectForKey:PHImageResultIsDegradedKey] boolValue]);
            }
            // Download image from iCloud / 从iCloud下载图片
            if ([info objectForKey:PHImageResultIsInCloudKey] && !result && networkAccessAllowed) {
                PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
                options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        if (progressHandler) {
                            progressHandler(progress, error, stop, info);
                        }
                    });
                };
                options.networkAccessAllowed = YES;
                options.resizeMode = PHImageRequestOptionsResizeModeFast;
                [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
                    UIImage *resultImage = [UIImage imageWithData:imageData scale:0.1];
                    resultImage = [self scaleImage:resultImage toSize:imageSize];
                    if (!resultImage) {
                        resultImage = image;
                    }
                    resultImage = [self fixOrientation:resultImage];
                    if (completion) completion(resultImage,info,NO);
                }];
            }
        }];
        return imageRequestID;
    } else if ([asset isKindOfClass:[ALAsset class]]) {
        ALAsset *alAsset = (ALAsset *)asset;
        dispatch_async(dispatch_get_global_queue(0,0), ^{
            CGImageRef thumbnailImageRef = alAsset.thumbnail;
            UIImage *thumbnailImage = [UIImage imageWithCGImage:thumbnailImageRef scale:2.0 orientation:UIImageOrientationUp];
            dispatch_async(dispatch_get_main_queue(), ^{
                if (completion) completion(thumbnailImage,nil,YES);
                
                if (photoWidth == JSScreenWidth || photoWidth == _photoPreviewMaxWidth) {
                    dispatch_async(dispatch_get_global_queue(0,0), ^{
                        ALAssetRepresentation *assetRep = [alAsset defaultRepresentation];
                        CGImageRef fullScrennImageRef = [assetRep fullScreenImage];
                        UIImage *fullScrennImage = [UIImage imageWithCGImage:fullScrennImageRef scale:2.0 orientation:UIImageOrientationUp];
                        
                        dispatch_async(dispatch_get_main_queue(), ^{
                            if (completion) completion(fullScrennImage,nil,NO);
                        });
                    });
                }
            });
        });
    }
    return 0;
}

至此关于photo获取资源的方法全部结束


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容

  • 相册适配 前言 由于在iOS8及以后苹果将原有的操作相册的ALAssetsLibrary framework替换为...
    wentianen阅读 1,792评论 0 6
  • 本文转载自Kayo Lee发表的文章,本文链接:http://kayosite.com/ios-developme...
    JackyHeWei阅读 10,417评论 10 10
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • demo下载地址在最下方 一、AssetsLibrary iOS提供的AssetsLibrary是用来读取和操作本...
    Archer_bling阅读 5,981评论 19 23
  • 没有等到月光和花开 也没有等到晨风和离别的问候 在我眼中 相遇可以无数遍 可我爱你,只有一遍 可你不爱我,也只有一...
    子禾CC阅读 123评论 0 0