相冊(cè) - PhotoKit

一服球、 PhotoKit的變量:

PHAdjustmentData?:

When a user edits an asset, photos saces a PHAdjustmentData object along with the modified image or video data;

在用戶(hù)編輯一個(gè)Asset時(shí)寻狂, 相冊(cè)會(huì)存儲(chǔ)該Asset在修改image或者video數(shù)據(jù)的過(guò)程

PHFetchOptions:

獲取資源時(shí)的參數(shù), 可以傳nil, 即使用系統(tǒng)默認(rèn)值宪迟。

PHFetchResult:

表示一系列的資源結(jié)果集合,也可以是相冊(cè)的集合, 從PHCollection的類(lèi)方法中獲得檩小。

PHImageManager:

用于處理資源的加載, 加載圖片的過(guò)程帶有緩存處理烟勋,可以通過(guò)傳入一個(gè)PHImageRequestOptions控制資源的輸出尺寸等規(guī)格规求。

PHImageRequestOptions:

控制加載圖片時(shí)的一系列參數(shù)。

PHAsset:

A PHAsset object represent an image or video file that appears in the Photos app, including iCloud Photos content.

一個(gè)PHAsset對(duì)象代表相冊(cè)中或者云儲(chǔ)存中的一個(gè)image或者Video文件卵惦;

PHAssetChangeRequest:

you create and use PHAssetChangeRequest objects within a photo library change block to create, delete ,or modify PHAsset objects.

當(dāng)你在相冊(cè)中增刪改PHAsset對(duì)象時(shí)需要使用PHAssetChangeRequest對(duì)象阻肿。

PHAssetCreationRequest:

a PHAssetCreationRequest object , used within a photo library change block, constructs a new photo or video asset from data resources, ?and adds it to the photos library;

PHAssetCreationRequest對(duì)象用于在照片庫(kù)的增刪改查操作,創(chuàng)建一個(gè)新的image和video Asset從Data resources中沮尿, 然后將其加入Photos Library中丛塌;

PHAssetCollectionChangeRequest:

you create and use PHAssetCollectionChangeRequest objects within a photo library change block to create, delete, or modigy PHAssetCollection objects;

當(dāng)你對(duì)photo Library 即 assetCollection進(jìn)行增刪改操作時(shí), 使用PHAssetCollectionChangeRequest對(duì)象

PHAssetResourceCreationOptions:

you use a PHAssetResourceCreationOptions abject to specify options when creating a new asset from data resources with a PHAssetCreationRequest Object.

通過(guò)PHAssetResourceCreationOptions對(duì)象來(lái)指定當(dāng)創(chuàng)建新的Asset的options畜疾;

PHAssetResourceManager:

PHAssetResourceManager 對(duì)象提供方法訪(fǎng)問(wèn)關(guān)聯(lián)相機(jī)Asset資源的基礎(chǔ)數(shù)據(jù)存儲(chǔ)

PHAssetCollection:

PHCollection的子類(lèi)赴邻, 表示一個(gè)相冊(cè)或者一個(gè)時(shí)刻, 或者一個(gè)智能相冊(cè)(系統(tǒng)提供的特定相冊(cè))啡捶。

PHPhotoLibrary:(重點(diǎn))

公共的PHPhotoLibrary對(duì)象代表用戶(hù)的相冊(cè)庫(kù)姥敛,所有的圖片和相冊(cè)管理都要PHPhotoLibrary管理;

PHCollectionList:

表示一組PHCollection瞎暑, 它本身也是一個(gè)PHCollection彤敛, 因此PHCollection作為一個(gè)集合与帆,可以包含其他集合,這使到PhotoKit的組成比ALAssetsLibrary要復(fù)雜一些墨榄,

二玄糟、PhotoKit的機(jī)制

1)、獲取資源

PhotoKit 是采用“獲取”的方式拉取資源袄秩, 這些獲取的手段茶凳,都是一系列形如class func fetchXXX(..., options: PHFetchOptions) -> PHFetchResult的類(lèi)方法。具體使用哪個(gè)類(lèi)方法播揪, 則視乎需要獲取的是相冊(cè)贮喧、時(shí)刻還是西苑, 這類(lèi)方法中的Option充當(dāng)了過(guò)濾器的作用猪狈∠渎伲可以過(guò)濾相冊(cè)的類(lèi)型、日期雇庙、名稱(chēng)等谓形。從而直接獲取對(duì)應(yīng)的資源二不需要枚舉;

例如:

// 列出所有相冊(cè)智能相冊(cè)

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

// 列出所有用戶(hù)創(chuàng)建的相冊(cè)

PHFetchResult *topLevelUserCollections = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];

// 獲取所有資源的集合疆前,并按資源的創(chuàng)建時(shí)間排序

PHFetchOptions *options = [[PHFetchOptions alloc] init];

options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];

PHFetchResult *assetsFetchResults = [PHAsset fetchAssetsWithOptions:options];

如前面提到過(guò)的那樣寒跳,從PHAssetCollection獲取中獲取到的可以是相冊(cè)也可以是資源, 但無(wú)論是那種內(nèi)容竹椒, 都統(tǒng)一使用PHFetchResult對(duì)象封裝起來(lái)童太, 因此雖然PHAssetCollection回去到的結(jié)果可以是多樣的, 但通過(guò)PHFetchResult就可以使用統(tǒng)一的方法去處理這些內(nèi)容(即遍歷PHFetchResult)胸完;

例子:

// 列出所有相冊(cè)智能相冊(cè)

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

// 這時(shí) smartAlbums 中保存的應(yīng)該是各個(gè)智能相冊(cè)對(duì)應(yīng)的 PHAssetCollection

for (NSInteger i = 0; i < fetchResult.count; i++) {

// 獲取一個(gè)相冊(cè)(PHAssetCollection)

PHCollection *collection = fetchResult[i];

if ([collection isKindOfClass:[PHAssetCollection class]]) {

PHAssetCollection *assetCollection = (PHAssetCollection *)collection;

// 從每一個(gè)智能相冊(cè)中獲取到的 PHFetchResult 中包含的才是真正的資源(PHAsset)

PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:fetchOptions];

else {

NSAssert(NO, @"Fetch collection not PHCollection: %@", collection);

}

}

// 獲取所有資源的集合书释,并按資源的創(chuàng)建時(shí)間排序

PHFetchOptions *options = [[PHFetchOptions alloc] init];

options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];

PHFetchResult *assetsFetchResults = [PHAsset fetchAssetsWithOptions:options];

// 這時(shí) assetsFetchResults 中包含的,應(yīng)該就是各個(gè)資源(PHAsset)

for (NSInteger i = 0; i < fetchResult.count; i++) {

// 獲取一個(gè)資源(PHAsset)

PHAsset *asset = fetchResult[i];

}

2)赊窥、獲取圖像的方式與坑點(diǎn):

PhotoKit無(wú)法直接從PHAsset的實(shí)體中獲取圖像爆惧,而引入了一個(gè)管理器PHImageManager獲取圖像,PHImageManager是通過(guò)請(qǐng)求的方式拉取圖像锨能,并可以控制請(qǐng)求得到的圖像的尺寸扯再、剪切方式、質(zhì)量址遇、緩存及請(qǐng)求本身的管理(發(fā)出請(qǐng)求熄阻、取消請(qǐng)求)等,而請(qǐng)求圖像的方法是PHImageManager的一個(gè)實(shí)例方法:

- (PHImageRequestID)requestImageForAsset:(PHAsset *)asset

targetSize:(CGSize)targetSize

contentMode:(PHImageContentMode)contentMode

options:(nullable PHImageRequestOptions *)options

resultHandler:(void (^)(UIImage *__nullable result, NSDictionary *__nullable info))resultHandler;

這個(gè)方法中的參數(shù)坑點(diǎn)不少傲隶,下面逐個(gè)參數(shù)舉例一下其作用及坑點(diǎn):

Asset: 圖像對(duì)應(yīng)的PHAsset饺律。

targetSize: 需要獲取的圖像的尺寸, 如果輸入的尺寸大于資源原圖的尺寸, 則需要返回原圖复濒。

注意:在PHImageManager中脖卖, 所有的尺寸都是用Pixel作為單位(note that all sizes are in pixels),因此這里想要獲取正確大大小圖像, 需要把輸入的尺寸轉(zhuǎn)為Pixel巧颈。如果需要返回原圖尺寸畦木,可以傳入PhotoKit中預(yù)先定義到的常量PHImageManagerMaximumSize, 表示返回可選范圍的最大尺寸砸泛, 即原圖尺寸十籍;

contentMode: 圖像的剪切方式, 與UIView的contentMode參數(shù)相似唇礁,控制照片應(yīng)該按比例縮放還是按比例填充的方式放到最終展示容器內(nèi)勾栗;

注意:如果targetSize傳入PHImageManagerMaximumSize, 則contentMode無(wú)論傳入什么指都會(huì)被視為PHImageContentModeDefault盏筐。

options: 一個(gè)PHImageRequestOptions的實(shí)例围俘,可以控制的內(nèi)容相當(dāng)豐富, 包含圖形的質(zhì)量琢融、版本界牡,也會(huì)有參數(shù)控制圖像的剪切,下面在展開(kāi)說(shuō)明漾抬;

resultHandler:請(qǐng)求結(jié)束后輩調(diào)用的Block宿亡, 返回喲呵包含資源對(duì)于圖像的UIImage和包含圖像信息的一個(gè)NSDictionary, 在整個(gè)請(qǐng)求的周期中纳令, 這個(gè)block可能會(huì)被調(diào)用多次挽荠,關(guān)于這點(diǎn)連同options參數(shù)在下面展開(kāi)說(shuō)明;

3)泊碑、PHImageRequestOptions與iCloud照片庫(kù):

PHImageRequestOptions中包含了一系列控制請(qǐng)求圖像的屬性坤按。

①毯欣、?resizeMode屬性控制圖像的剪切馒过,不知道為什么PhotoKit會(huì)在請(qǐng)求圖像方法(requestImageForAsset)中已經(jīng)有控制圖像剪切的參數(shù)后(contentMode),還在options中加入控制剪切屬性酗钞, 但如果兩個(gè)地方所控制的剪切結(jié)果有所沖突腹忽, PhotoKit會(huì)以resizeMode的結(jié)果為準(zhǔn)。另外砚作,resizeMode也有控制圖形質(zhì)量的作用窘奏,如resizeMode設(shè)置為PHImageRequestOptionsResizeModeExact則返回圖像必須和目標(biāo)代銷(xiāo)匹配,并且圖形質(zhì)量也為高質(zhì)量圖像葫录,而設(shè)置為PHImageRequestOptionsResizeModeFast則請(qǐng)求的效率更高着裹,但返回的圖像可能和目標(biāo)大小不一樣并且質(zhì)量較低。

②米同、在PhotoKit中骇扇, 對(duì)iCloud照片庫(kù)有很好的支持摔竿,如果用戶(hù)開(kāi)啟了iCloud照片庫(kù), 并且選擇了“優(yōu)化iPhone少孝、iPad存儲(chǔ)空間”继低, 或者選擇了“下載并保留原件”但原件內(nèi)有加載好的時(shí)候, PhotoKit也會(huì)預(yù)選拿到這些非本地圖像的PHAsset稍走, 但是由于本地并沒(méi)有原圖袁翁,所以如果產(chǎn)生了請(qǐng)求高清圖的請(qǐng)求, PhotoKit會(huì)嘗試從iCloud現(xiàn)在圖片婿脸, 而這個(gè)行為最終的表現(xiàn)粱胜,會(huì)被PHImageRequestOptions中的值所影響。PHImageRequestOptions中常常會(huì)用到幾個(gè)屬性:

例如:

1狐树、networkAccessAllowed:此參數(shù)控制時(shí)候允許網(wǎng)絡(luò)請(qǐng)求年柠, 默認(rèn)是NO。如果不允許網(wǎng)絡(luò)請(qǐng)求褪迟, 那么不用設(shè)置冗恨;當(dāng)然也拉取不到iCloud的圖像原件;

2味赃、deliveryMode: 則用于控制請(qǐng)求圖片質(zhì)量掀抹;

3、synchronous: 控制是否為同步請(qǐng)求心俗, 默認(rèn)為NO傲武,如果為YES, 即同步請(qǐng)求時(shí)城榛,deliveryMode會(huì)被視為PHImageRequestOptionsDeliveryModeHighQualityFormat揪利, 即自動(dòng)返回高質(zhì)量的圖片, 因此不建議使用同步請(qǐng)求狠持,否則如果界面需要等待返回的圖像才能進(jìn)一步做出反應(yīng)疟位,則反應(yīng)時(shí)長(zhǎng)會(huì)很長(zhǎng)。

4喘垂、progressHandler: 當(dāng)圖片需要從iCloud下載時(shí)甜刻, 這個(gè)block會(huì)被自動(dòng)調(diào)用,block中會(huì)返回圖像下載的進(jìn)度正勒、圖像的信息得院、出錯(cuò)信息。開(kāi)發(fā)者可以利用這些信息反饋給用戶(hù)當(dāng)前圖形的現(xiàn)在進(jìn)度以及狀態(tài)章贞。但需要注意progressHandler不在主線(xiàn)程上執(zhí)行祥绞, 因此在其中需要操作UI, 則需要手動(dòng)放到主線(xiàn)程執(zhí)行;

5蜕径、versions: 這個(gè)屬性是指獲取的圖像是否包含系統(tǒng)相冊(cè)“編輯”功能處理過(guò)的信息(如濾鏡怪蔑、旋轉(zhuǎn)等), 這點(diǎn)比ALAssetLibrary要靈活丧荐,

③缆瓣、上面提到,requestImageForAsset中的參數(shù)resultHandler可能會(huì)被多次調(diào)用虹统,這種情況就是圖片需要從iCloud中下載的情況弓坞,在requestImageForAsset中返回的內(nèi)容中,一開(kāi)始的那一次請(qǐng)求中會(huì)返回一個(gè)小尺寸的圖像版本车荔,當(dāng)高清圖像還在下載時(shí)渡冻, 開(kāi)發(fā)者可以首先給用戶(hù)展示這個(gè)低清的圖像版本,然后block在多次調(diào)用后忧便, 最終返回高清的原圖族吻, 至于當(dāng)前返回的圖像是哪兒個(gè)版本圖像,可以通過(guò)block返回的NSDictionary info中獲知珠增,PHImageResultlsDegradedKey表示當(dāng)前返回的UIImage是低清圖超歌,如果判斷是否已經(jīng)獲得高清圖,可以這樣判斷:

// 排除取消蒂教,錯(cuò)誤巍举,低清圖三種情況,即已經(jīng)獲取到了高清圖

BOOL downloadFinined = ![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue];

注意:

當(dāng)我們使用requestImageForAsset發(fā)出對(duì)圖像的請(qǐng)求時(shí)凝垛, 如果在同一個(gè)PHImageManager中同時(shí)對(duì)同一個(gè)資源發(fā)出圖像請(qǐng)求懊悯, 請(qǐng)求的進(jìn)度是可以共享的,因此我們可以利用這個(gè)特性梦皮, 吧PHImageManager以單例的形式使用炭分, 這樣在切換界面時(shí)也不用擔(dān)心無(wú)法傳遞原圖的下載進(jìn)度, 例如:在圖像的列表頁(yè)面觸發(fā)了下載圖像剑肯, 當(dāng)我們離開(kāi)列表頁(yè)面進(jìn)入預(yù)覽大圖界面時(shí)捧毛, 并不用擔(dān)心會(huì)重新下載圖像, 只要沒(méi)有手動(dòng)取消圖像下載退子, 進(jìn)入大圖預(yù)覽界面下載圖像會(huì)自動(dòng)繼續(xù)從上次的僅需下載圖像岖妄。

如果需要取消下載圖像,則可以使用PHImageManager的cancelImageRequest方法寂祥, 它傳入的是請(qǐng)求圖像的請(qǐng)求ID, 這個(gè)ID可以從requestImageForAsset的返回值中獲得七兜,當(dāng)然也可以從前面提到的包含圖形信息的NSDictionary info中獲得丸凭,當(dāng)然前提是這和接受取消的PHImageManager與剛剛發(fā)送請(qǐng)求的PHImageManager是同一個(gè)實(shí)例,如上面所述式樣單例是最為簡(jiǎn)單有效的方式;

4)惜犀、獲取圖像的優(yōu)化:

PHImageManager提供了一個(gè)子類(lèi)PHImageCachingManager用于處理圖像的緩存铛碑,但是這個(gè)子類(lèi)并不只是圖像本身的緩存, 而是更加實(shí)用—處理圖形的整個(gè)加載過(guò)程的緩存

- (void)startCachingImagesForAssets:(NSArray *)assets targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode options:(nullable PHImageRequestOptions *)options;

總結(jié)更為簡(jiǎn)易可行的緩存方法:

獲取圖像時(shí)盡量獲取預(yù)覽圖虽界,不要直接顯示原件汽烦,建議獲取與設(shè)備屏統(tǒng)樣大小的圖像即可,實(shí)際系統(tǒng)相冊(cè)預(yù)覽大圖時(shí)使用的也是預(yù)覽圖莉御,這也是系統(tǒng)相冊(cè)加載速度快的原因撇吞。

獲取圖片使用異步請(qǐng)求, 如上面所述礁叔, 當(dāng)請(qǐng)求為異步時(shí)返回圖像的block會(huì)被多次調(diào)用牍颈,先返回低清圖,再返回高清圖琅关, 這樣一來(lái)可以大大減少UI的等待時(shí)間煮岁。

獲取到高清圖后可以緩存下來(lái), 簡(jiǎn)單的使用變量緩存即可涣易,盡量在獲取高清圖后避免再次發(fā)起請(qǐng)求獲取圖像画机, 因?yàn)榧词箞D像原件已經(jīng)下載了,從新請(qǐng)求高清圖時(shí)因?yàn)閳D片的尺寸比較大新症, 因此系統(tǒng)會(huì)生成圖形和剪切圖形也會(huì)話(huà)費(fèi)一些時(shí)間色罚;

預(yù)先加載圖像, 如像預(yù)覽大圖這類(lèi)情景中账劲, 用戶(hù)同時(shí)只會(huì)看到一張大圖戳护,因此在觀(guān)看某一張圖片時(shí),預(yù)先請(qǐng)求其鄰近兩張圖片瀑焦, 對(duì)于加快UI響應(yīng)很有幫助腌且。

三、常用方法的封裝:

1)榛瓮、原圖:

由于原圖的尺寸通常會(huì)比較大铺董,因此建議使用異步拉取, 但這里仍同時(shí)列舉同步拉取方法禀晓,這里需要留意如前文總所述精续,ALAssetRepresentation中獲取原圖的接口fullResolutionImage所得到的圖像并沒(méi)有帶上系統(tǒng)相冊(cè)“編輯”(選擇, 濾鏡等)效果粹懒。 需要額外獲取這些效果并手工疊加到圖像上重付。

.h文件

/// Asset 的原圖(包含系統(tǒng)相冊(cè)“編輯”功能處理后的效果)

- (UIImage *)originImage;

/**

*? 異步請(qǐng)求 Asset 的原圖,包含了系統(tǒng)照片“編輯”功能處理后的效果(剪裁凫乖,旋轉(zhuǎn)和濾鏡等)确垫,可能會(huì)有網(wǎng)絡(luò)請(qǐng)求

*

*? @param completion??????? 完成請(qǐng)求后調(diào)用的 block弓颈,參數(shù)中包含了請(qǐng)求的原圖以及圖片信息,在 iOS 8.0 或以上版本中删掀,

*?????????????????????????? 這個(gè) block 會(huì)被多次調(diào)用翔冀,其中第一次調(diào)用獲取到的尺寸很小的低清圖,然后不斷調(diào)用披泪,直接獲取到高清圖纤子,

*?????????????????????????? 獲取到高清圖后 QMUIAsset 會(huì)緩存起這張高清圖,這時(shí) block 中的第二個(gè)參數(shù)(圖片信息)返回的為 nil款票。

*? @param phProgressHandler 處理請(qǐng)求進(jìn)度的 handler控硼,不在主線(xiàn)程上執(zhí)行,在 block 中修改 UI 時(shí)注意需要手工放到主線(xiàn)程處理徽职。

*

*? @wraning iOS 8.0 以下中并沒(méi)有異步請(qǐng)求預(yù)覽圖的接口象颖,因此實(shí)際上為同步請(qǐng)求,這時(shí) block 中的第二個(gè)參數(shù)(圖片信息)返回的為 nil姆钉。

*

*? @return 返回請(qǐng)求圖片的請(qǐng)求 id

*/

- (NSInteger)requestOriginImageWithCompletion:(void (^)(UIImage *, NSDictionary *))completion withProgressHandler:(PHAssetImageProgressHandler)phProgressHandler;

.m文件

- (UIImage *)originImage {

if (_originImage) {

return _originImage;

}

__block UIImage *resultImage;

if (_usePhotoKit) {

PHImageRequestOptions *phImageRequestOptions = [[PHImageRequestOptions alloc] init];

phImageRequestOptions.synchronous = YES;

[[[QMUIAssetsManager sharedInstance] phCachingImageManager] requestImageForAsset:_phAsset

targetSize:PHImageManagerMaximumSize

contentMode:PHImageContentModeDefault

options:phImageRequestOptions

resultHandler:^(UIImage *result, NSDictionary *info) {

resultImage = result;

}];

} else {

CGImageRef fullResolutionImageRef = [_alAssetRepresentation fullResolutionImage];

// 通過(guò) fullResolutionImage 獲取到的的高清圖實(shí)際上并不帶上在照片應(yīng)用中使用“編輯”處理的效果说订,需要額外在 AlAssetRepresentation 中獲取這些信息

NSString *adjustment = [[_alAssetRepresentation metadata] objectForKey:@"AdjustmentXMP"];

if (adjustment) {

// 如果有在照片應(yīng)用中使用“編輯”效果,則需要獲取這些編輯后的濾鏡潮瓶,手工疊加到原圖中

NSData *xmpData = [adjustment dataUsingEncoding:NSUTF8StringEncoding];

CIImage *tempImage = [CIImage imageWithCGImage:fullResolutionImageRef];

NSError *error;

NSArray *filterArray = [CIFilter filterArrayFromSerializedXMP:xmpData

inputImageExtent:tempImage.extent

error:&error];

CIContext *context = [CIContext contextWithOptions:nil];

if (filterArray && !error) {

for (CIFilter *filter in filterArray) {

[filter setValue:tempImage forKey:kCIInputImageKey];

tempImage = [filter outputImage];

}

fullResolutionImageRef = [context createCGImage:tempImage fromRect:[tempImage extent]];

}

}

// 生成最終返回的 UIImage陶冷,同時(shí)把圖片的 orientation 也補(bǔ)充上去

resultImage = [UIImage imageWithCGImage:fullResolutionImageRef scale:[_alAssetRepresentation scale] orientation:(UIImageOrientation)[_alAssetRepresentation orientation]];

}

_originImage = resultImage;

return resultImage;

}

- (NSInteger)requestOriginImageWithCompletion:(void (^)(UIImage *, NSDictionary *))completion withProgressHandler:(PHAssetImageProgressHandler)phProgressHandler {

if (_usePhotoKit) {

if (_originImage) {

// 如果已經(jīng)有緩存的圖片則直接拿緩存的圖片

if (completion) {

completion(_originImage, nil);

}

return 0;

} else {

PHImageRequestOptions *imageRequestOptions = [[PHImageRequestOptions alloc] init];

imageRequestOptions.networkAccessAllowed = YES; // 允許訪(fǎng)問(wèn)網(wǎng)絡(luò)

imageRequestOptions.progressHandler = phProgressHandler;

return [[[QMUIAssetsManager sharedInstance] phCachingImageManager] requestImageForAsset:_phAsset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:imageRequestOptions resultHandler:^(UIImage *result, NSDictionary *info) {

// 排除取消,錯(cuò)誤毯辅,低清圖三種情況埂伦,即已經(jīng)獲取到了高清圖時(shí),把這張高清圖緩存到 _originImage 中

BOOL downloadFinined = ![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue];

if (downloadFinined) {

_originImage = result;

}

if (completion) {

completion(result, info);

}

}];

}

} else {

if (completion) {

completion([self originImage], nil);

}

return 0;

}

}

2)思恐、縮略圖

相對(duì)于在拉取原圖時(shí) ALAssetLibrary 的部分需要手工疊加系統(tǒng)相冊(cè)的“編輯”效果沾谜,拉取縮略圖則簡(jiǎn)單一些,因?yàn)橄到y(tǒng)接口拉取到的縮略圖已經(jīng)帶上“編輯”的效果了胀莹。

.h文件

/**

*? Asset 的縮略圖

*

*? @param size 指定返回的縮略圖的大小基跑,僅在 iOS 8.0 及以上的版本有效,其他版本則調(diào)用 ALAsset 的接口由系統(tǒng)返回一個(gè)合適當(dāng)前平臺(tái)的圖片

*

*? @return Asset 的縮略圖

*/

- (UIImage *)thumbnailWithSize:(CGSize)size;

/**

*? 異步請(qǐng)求 Asset 的縮略圖描焰,不會(huì)產(chǎn)生網(wǎng)絡(luò)請(qǐng)求

*

*? @param size?????? 指定返回的縮略圖的大小媳否,僅在 iOS 8.0 及以上的版本有效,其他版本則調(diào)用 ALAsset 的接口由系統(tǒng)返回一個(gè)合適當(dāng)前平臺(tái)的圖片

*? @param completion 完成請(qǐng)求后調(diào)用的 block荆秦,參數(shù)中包含了請(qǐng)求的縮略圖以及圖片信息篱竭,在 iOS 8.0 或以上版本中,這個(gè) block 會(huì)被多次調(diào)用步绸,

*??????????????????? 其中第一次調(diào)用獲取到的尺寸很小的低清圖掺逼,然后不斷調(diào)用,直接獲取到高清圖靡努,獲取到高清圖后 QMUIAsset 會(huì)緩存起這張高清圖坪圾,

*??????????????????? 這時(shí) block 中的第二個(gè)參數(shù)(圖片信息)返回的為 nil晓折。

*

*? @return 返回請(qǐng)求圖片的請(qǐng)求 id

*/

- (NSInteger)requestThumbnailImageWithSize:(CGSize)size completion:(void (^)(UIImage *, NSDictionary *))completion;

.m 文件

- (UIImage *)thumbnailWithSize:(CGSize)size {

if (_thumbnailImage) {

return _thumbnailImage;

}

__block UIImage *resultImage;

if (_usePhotoKit) {

PHImageRequestOptions *phImageRequestOptions = [[PHImageRequestOptions alloc] init];

phImageRequestOptions.resizeMode = PHImageRequestOptionsResizeModeExact;

// 在 PHImageManager 中惑朦,targetSize 等 size 都是使用 px 作為單位兽泄,因此需要對(duì)targetSize 中對(duì)傳入的 Size 進(jìn)行處理,寬高各自乘以 ScreenScale漾月,從而得到正確的圖片

[[[QMUIAssetsManager sharedInstance] phCachingImageManager] requestImageForAsset:_phAsset

targetSize:CGSizeMake(size.width * ScreenScale, size.height * ScreenScale)

contentMode:PHImageContentModeAspectFill options:phImageRequestOptions

resultHandler:^(UIImage *result, NSDictionary *info) {

resultImage = result;

}];

} else {

CGImageRef thumbnailImageRef = [_alAsset thumbnail];

if (thumbnailImageRef) {

resultImage = [UIImage imageWithCGImage:thumbnailImageRef];

}

}

_thumbnailImage = resultImage;

return resultImage;

}

- (NSInteger)requestThumbnailImageWithSize:(CGSize)size completion:(void (^)(UIImage *, NSDictionary *))completion {

if (_usePhotoKit) {

if (_thumbnailImage) {

if (completion) {

completion(_thumbnailImage, nil);

}

return 0;

} else {

PHImageRequestOptions *imageRequestOptions = [[PHImageRequestOptions alloc] init];

imageRequestOptions.resizeMode = PHImageRequestOptionsResizeModeExact;

// 在 PHImageManager 中病梢,targetSize 等 size 都是使用 px 作為單位,因此需要對(duì)targetSize 中對(duì)傳入的 Size 進(jìn)行處理梁肿,寬高各自乘以 ScreenScale蜓陌,從而得到正確的圖片

return [[[QMUIAssetsManager sharedInstance] phCachingImageManager] requestImageForAsset:_phAsset targetSize:CGSizeMake(size.width * ScreenScale, size.height * ScreenScale) contentMode:PHImageContentModeAspectFill options:imageRequestOptions resultHandler:^(UIImage *result, NSDictionary *info) {

// 排除取消,錯(cuò)誤吩蔑,低清圖三種情況钮热,即已經(jīng)獲取到了高清圖時(shí),把這張高清圖緩存到 _thumbnailImage 中

BOOL downloadFinined = ![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue];

if (downloadFinined) {

_thumbnailImage = result;

}

if (completion) {

completion(result, info);

}

}];

}

} else {

if (completion) {

completion([self thumbnailWithSize:size], nil);

}

return 0;

}

}

3)烛芬、 預(yù)覽圖

與上面的方法類(lèi)似隧期,不再展開(kāi)說(shuō)明。

.h 文件

/**

*? Asset 的預(yù)覽圖

*

*? @warning 仿照 ALAssetsLibrary 的做法輸出與當(dāng)前設(shè)備屏幕大小相同尺寸的圖片赘娄,如果圖片原圖小于當(dāng)前設(shè)備屏幕的尺寸仆潮,則只輸出原圖大小的圖片

*? @return Asset 的全屏圖

*/

- (UIImage *)previewImage;

/**

*? 異步請(qǐng)求 Asset 的預(yù)覽圖,可能會(huì)有網(wǎng)絡(luò)請(qǐng)求

*

*? @param completion??????? 完成請(qǐng)求后調(diào)用的 block遣臼,參數(shù)中包含了請(qǐng)求的預(yù)覽圖以及圖片信息性置,在 iOS 8.0 或以上版本中,

*?????????????????????????? 這個(gè) block 會(huì)被多次調(diào)用揍堰,其中第一次調(diào)用獲取到的尺寸很小的低清圖鹏浅,然后不斷調(diào)用,直接獲取到高清圖屏歹,

*?????????????????????????? 獲取到高清圖后 QMUIAsset 會(huì)緩存起這張高清圖隐砸,這時(shí) block 中的第二個(gè)參數(shù)(圖片信息)返回的為 nil。

*? @param phProgressHandler 處理請(qǐng)求進(jìn)度的 handler西采,不在主線(xiàn)程上執(zhí)行凰萨,在 block 中修改 UI 時(shí)注意需要手工放到主線(xiàn)程處理。

*

*? @wraning iOS 8.0 以下中并沒(méi)有異步請(qǐng)求預(yù)覽圖的接口械馆,因此實(shí)際上為同步請(qǐng)求胖眷,這時(shí) block 中的第二個(gè)參數(shù)(圖片信息)返回的為 nil。

*

*? @return 返回請(qǐng)求圖片的請(qǐng)求 id

*/

- (NSInteger)requestPreviewImageWithCompletion:(void (^)(UIImage *, NSDictionary *))completion withProgressHandler:(PHAssetImageProgressHandler)phProgressHandler;

.m 文件

- (UIImage *)previewImage {

if (_previewImage) {

return _previewImage;

}

__block UIImage *resultImage;

if (_usePhotoKit) {

PHImageRequestOptions *imageRequestOptions = [[PHImageRequestOptions alloc] init];

imageRequestOptions.synchronous = YES;

[[[QMUIAssetsManager sharedInstance] phCachingImageManager] requestImageForAsset:_phAsset

targetSize:CGSizeMake(SCREEN_WIDTH, SCREEN_HEIGHT)

contentMode:PHImageContentModeAspectFill

options:imageRequestOptions

resultHandler:^(UIImage *result, NSDictionary *info) {

resultImage = result;

}];

} else {

CGImageRef fullScreenImageRef = [_alAssetRepresentation fullScreenImage];

resultImage = [UIImage imageWithCGImage:fullScreenImageRef];

}

_previewImage = resultImage;

return resultImage;

}

- (NSInteger)requestPreviewImageWithCompletion:(void (^)(UIImage *, NSDictionary *))completion withProgressHandler:(PHAssetImageProgressHandler)phProgressHandler {

if (_usePhotoKit) {

if (_previewImage) {

// 如果已經(jīng)有緩存的圖片則直接拿緩存的圖片

if (completion) {

completion(_previewImage, nil);

}

return 0;

} else {

PHImageRequestOptions *imageRequestOptions = [[PHImageRequestOptions alloc] init];

imageRequestOptions.networkAccessAllowed = YES; // 允許訪(fǎng)問(wèn)網(wǎng)絡(luò)

imageRequestOptions.progressHandler = phProgressHandler;

return [[[QMUIAssetsManager sharedInstance] phCachingImageManager] requestImageForAsset:_phAsset targetSize:CGSizeMake(SCREEN_WIDTH, SCREEN_HEIGHT) contentMode:PHImageContentModeAspectFill options:imageRequestOptions resultHandler:^(UIImage *result, NSDictionary *info) {

// 排除取消霹崎,錯(cuò)誤珊搀,低清圖三種情況,即已經(jīng)獲取到了高清圖時(shí)尾菇,把這張高清圖緩存到 _previewImage 中

BOOL downloadFinined = ![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue];

if (downloadFinined) {

_previewImage = result;

}

if (completion) {

completion(result, info);

}

}];

}

} else {

if (completion) {

completion([self previewImage], nil);

}

return 0;

}

}

4)境析、方向(imageOrientation)

比較奇怪的是囚枪,無(wú)論在 PhotoKit 或者是 ALAssetLibrary 中,要想獲取到準(zhǔn)確的圖像方向劳淆,只能通過(guò)某些 key 檢索所得链沼。

.h 文件

- (UIImageOrientation)imageOrientation;

.m文件

- (UIImageOrientation)imageOrientation {

UIImageOrientation orientation;

if (_usePhotoKit) {

if (!_phAssetInfo) {

// PHAsset 的 UIImageOrientation 需要調(diào)用過(guò) requestImageDataForAsset 才能獲取

[self requestPhAssetInfo];

}

// 從 PhAssetInfo 中獲取 UIImageOrientation 對(duì)應(yīng)的字段

orientation = (UIImageOrientation)[_phAssetInfo[@"orientation"] integerValue];

} else {

orientation = (UIImageOrientation)[[_alAsset valueForProperty:@"ALAssetPropertyOrientation"] integerValue];

}

return orientation;

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市沛鸵,隨后出現(xiàn)的幾起案子括勺,更是在濱河造成了極大的恐慌,老刑警劉巖曲掰,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疾捍,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡栏妖,警方通過(guò)查閱死者的電腦和手機(jī)乱豆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)吊趾,“玉大人宛裕,你說(shuō)我怎么就攤上這事≈夯眨” “怎么了续滋?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)孵奶。 經(jīng)常有香客問(wèn)我疲酌,道長(zhǎng),這世上最難降的妖魔是什么了袁? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任朗恳,我火速辦了婚禮,結(jié)果婚禮上载绿,老公的妹妹穿的比我還像新娘粥诫。我一直安慰自己,他們只是感情好崭庸,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布怀浆。 她就那樣靜靜地躺著,像睡著了一般怕享。 火紅的嫁衣襯著肌膚如雪执赡。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,718評(píng)論 1 305
  • 那天函筋,我揣著相機(jī)與錄音沙合,去河邊找鬼。 笑死跌帐,一個(gè)胖子當(dāng)著我的面吹牛首懈,可吹牛的內(nèi)容都是我干的绊率。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼究履,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼滤否!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起挎袜,我...
    開(kāi)封第一講書(shū)人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤顽聂,失蹤者是張志新(化名)和其女友劉穎肥惭,沒(méi)想到半個(gè)月后盯仪,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蜜葱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年全景,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片牵囤。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡爸黄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出揭鳞,到底是詐尸還是另有隱情炕贵,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布野崇,位于F島的核電站称开,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏乓梨。R本人自食惡果不足惜鳖轰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望扶镀。 院中可真熱鬧蕴侣,春花似錦、人聲如沸臭觉。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蝠筑。三九已至狞膘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間菱肖,已是汗流浹背客冈。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留稳强,地道東北人场仲。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓和悦,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親渠缕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鸽素,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容