PhotoKit詳解


Photokit介紹

這篇主要介紹如何通過 Photokit獲取數據

photokit.jpg
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
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;
}

 

本文章轉自:http://www.jianshu.com/p/119bd419c172


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM