PhotoKit详解
Photokit介绍
这篇主要介绍如何通过 Photokit获取数据
1,基类 PHObject
Photos 框架中的根类PHObject只有一个公开接口 localIdentifier,是对象唯一标志符.PHObject实现了-isEqual 和-hash方法.可以直接使用localIdentifier属性对PHObject及其子类对象进行对比是否同一个对象
2,数据类型
PHAsset 、PHAssetCollection、PHCollectionList 是Photos框架中的模型类
PHAsset :代表系统的一个图片,视频或者Live Photo
PHAssetCollection:是一组有序的资源集合,包括相册、moments、智能相册以及共享照片流.比如:系统相册里的时刻一个分类,用户创建的相册或者智能相册
PHCollectionList : 相册集合, 比如:时刻里的年或者包含用户创建的一个或者多个相册
表示一组PHCollection,而它本身也是一个PHCollection,因此PHCollection作为一个集合,可以包含其他集合
如下资源结构图:
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;
}
本文章转自:http://www.jianshu.com/p/119bd419c172