一服球、 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;
}