iOS-對圖片操作---新增到自定義相簿

weixin_34075551發表於2018-09-11

圖片操作---新增到自定義相簿

實際上,自定義相簿中的圖片並不是實際的圖片,而是對系統【相機膠捲】這個相簿中的圖片進行一個引用,所以將圖片儲存到自定義相簿的第一步就是先儲存到系統的【相機膠捲】中...

1.步驟

• 將圖片儲存到系統相簿【相機膠捲】中

(1)C語言函式來儲存
(2)AssetsLibrary框架--系統自帶,iOS9廢棄
(3)Photos框架--系統自帶,iOS8即可使用,取代AssetsLibrary

• 是否存在自定義相簿(沒有則建立)將圖片新增到自定義相簿

 AssetsLibrary
 Photos

2.Photos 框架介紹

2.1 重要的類

該框架有幾個非常重要的類:PHAsset、PHAssetCollection 和 PHLibrary。

• PHAsset 表示一個圖片或者視訊檔案(儲存在手機的照片 APP 中的)。與具體圖片有關的使用這個類
• PHAssetCollection 表示圖片集合或者視訊集合,其實就是指相簿(包括系統相簿和自定義相簿)
• PHLibrary 表示整個相簿庫,包括整個相簿和圖片等

注:只要與單個圖片相關,使用 PHAsset。只要與相簿相關,使用 PHAssetCollection

2.2 查詢操作

查詢操作,直接使用 PHAsset 和 PHAssetCollection 類本身的方法

// 獲取相簿中的圖片--傳入相簿圖片的ID---返回一組圖片
[PHAsset fetchAssetsWithLocalIdentifiers:@[ID] options:nil];

// 查詢手機中所有的相簿列表(分為系統相簿和自定義相簿,通過控制傳入的引數來確定)---返回相簿組--類似陣列-forin遍歷即可
[PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];

2.3 增刪改操作

1.如果做查詢之外的操作,比如說儲存圖片、建立自定義相簿、向自定義相簿中新增圖片等,都需要使用另外兩個類:PHAssetChangeRequest 和 PHAssetCollectionChangeRequest

2.這些操作必須在 [[PHPhotoLibrary sharedPhotoLibrary] performChange...]的 block 中間呼叫

3.將圖片儲存到系統相機【相機膠捲】中

3.1 C語言函式

儲存操作的程式碼:

// 把圖片儲存到系統相簿中,結束後呼叫 image:didFinishSavingWithError:contextInfo:方法(回撥方法)
// 回撥方法的格式有要求,可以進入標頭檔案檢視
UIImageWriteToSavedPhotosAlbum(self.imageView.image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);

實現回撥方法

- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
    if (error) {
        NSLog(@"儲存圖片失敗!");
        return;
    }
    NSLog(@"儲存圖片成功!");
}

3.2 Photos 框架儲存圖片到系統相簿

Photos 框架儲存圖片 --- 使用 PHAssetChangeRequest 類方法

有兩種方式:非同步方式和同步方式,但是儲存圖片的操作效能消耗不大,所以可以直接使用同步方式

3.2.1 非同步方式
- (void)asyncSaveImageWithPhotos {
    // 必須在 block 中呼叫
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        // 非同步執行儲存圖片操作
        [PHAssetChangeRequest creationRequestForAssetFromImage:self.imageView.image];
    } completionHandler:^(BOOL success, NSError * _Nullable error) {
        // 儲存結束後,回撥
        if (error) {
            [[AppDelegate app] showErrorAndAutoHide:@"儲存失敗!"];
        } else {
            [[AppDelegate app] showSuccessAndAutoHide:@"儲存成功!"];
        }
    }];
}
3.2.2 同步方式
- (PHFetchResult<PHAsset *> *)synchronousSaveImageWithPhotosWithImage:(UIImage *)image {
    __block NSString *createdAssetId = nil;
    
    // 新增圖片到【相機膠捲】
    [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
        createdAssetId = [PHAssetChangeRequest creationRequestForAssetFromImage:image].placeholderForCreatedAsset.localIdentifier;
    } error:nil];
    
    if (createdAssetId == nil) return nil;
    // 在儲存完畢後取出圖片
    return [PHAsset fetchAssetsWithLocalIdentifiers:@[createdAssetId] options:nil];
}

4.是否存在自定義相簿(沒有則建立)

如果沒有,則常見跟當前 APP 同名的自定義相簿

實現思路:
① 獲取當前專案的名字

NSString *titlePhotos = [NSBundle mainBundle].infoDictionary[(NSString *)kCFBundleNameKey];

② 使用PHAssetCollection的fetchAssetCollectionsWithType:subType:options方法,通過傳入型別,獲取所有的自定義相簿列表
③ 遍歷獲取的自定義相簿列表,與APP的名稱進行比對,匹配後返回當前同名的自定義相簿 PHAssetCollection物件
④ 如果沒有找到,則開始建立,在PHPhotoLibrary單例物件的perfromChange方法中執行建立自定義相簿操作
⑤ block中,儲存待建立相簿的佔位識別符號---其實這個時刻,相簿根本沒建立完成
⑥ 通過error判斷是否建立成功
⑦ 如果建立成功,通過PHAssetCollection的fetchAssetCollectionsWithLocalIdentifiers:options來獲取當前建立相簿物件PHAssetCollection

- (PHAssetCollection *)getAssetCollectionWithAppNameAndCreateCollection {
    NSString *titlePhotos = [NSBundle mainBundle].infoDictionary[(NSString *)kCFBundleNameKey];
    // 獲得所有的自定義相簿
    PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    for (PHAssetCollection *collection in collections) {
        if ([collection.localizedTitle isEqualToString:titlePhotos]) {
            return collection;
        }
    }
    
    NSError *error = nil;
    // 程式碼執行到這裡,說明還沒有自定義相簿
    __block NSString *createdCollectionId = nil;
    
    // 建立一個新的相簿
    [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
        createdCollectionId = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:titlePhotos].placeholderForCreatedAssetCollection.localIdentifier;
    } error:&error];
    
    if (error) {
        [[AppDelegate app] showErrorAndAutoHide:@"建立失敗!"];
        return nil;
    } else {
        [[AppDelegate app] showSuccessAndAutoHide:@"建立成功!"];
        // 建立完畢後再取出相簿
        return [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[createdCollectionId] options:nil].firstObject;
    }
}

5.把圖片新增到自定義相簿

實現思路
① 使用獲取的自定義相簿來建立PHAssetCollection物件
② 將剛才儲存到系統相簿的PHAsset儲存到相簿中

- (void)saveImageToCustomAblumWithImage:(UIImage *)image {
    // 將圖片儲存到系統的【相機膠捲】中---呼叫剛才的方法
    PHFetchResult<PHAsset *> *assets = [self synchronousSaveImageWithPhotosWithImage:image];
    if (assets == nil) {
        [[AppDelegate app] showErrorAndAutoHide:@"儲存失敗!"];
        return;
    }
    
    // 擁有自定義相簿(與 APP 同名,如果沒有則建立)--呼叫剛才的方法
    PHAssetCollection *assetCollection = [self getAssetCollectionWithAppNameAndCreateCollection];
    if (assetCollection == nil) {
        [[AppDelegate app] showErrorAndAutoHide:@"相簿建立失敗!"];
        return;
    }
    
    // 將剛才儲存到相機膠捲的圖片新增到自定義相簿中 --- 儲存帶自定義相簿--屬於增的操作,需要在PHPhotoLibrary的block中進行
    NSError *error = nil;
    [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
        //--告訴系統,要操作哪個相簿
        PHAssetCollectionChangeRequest *collectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
        //--新增圖片到自定義相簿--追加--就不能成為封面了
        //--[collectionChangeRequest addAssets:assets];
        //--插入圖片到自定義相簿--插入--可以成為封面
        [collectionChangeRequest insertAssets:assets atIndexes:[NSIndexSet indexSetWithIndex:0]];
    } error:&error];
    
    if (error) {
        [[AppDelegate app] showErrorAndAutoHide:@"儲存失敗!"];
        return;
    }
    [[AppDelegate app] showSuccessAndAutoHide:@"儲存成功!"];
}

6.相簿的授權訪問

當第一次使用APP的時候,或者第一次訪問相簿的時候,系統會彈出授權選擇對話方塊詢問使用者。所以我們在儲存圖片到相簿的時候,需要判斷當前是否授權。

6.1 許可權分類

PHAuthorizationStatusNotDetermined ,---使用者之前還未決定
PHAuthorizationStatusRestricted, ---系統問題,使用者沒有許可權決定--比如家長控制器模式
PHAuthorizationStatusDenied,---使用者之前拒絕過
PHAuthorizationStatusAuthorized --使用者允許

6.2 請求許可權的方式

可以使用NSPhotoLibrary的類方法requestAuthorization來檢視許可權,或者請求許可權。如果使用者之前沒做決定,則彈出系統對話方塊請求許可權;如果使用者做過決定,則呼叫該類方法的block。

儲存圖片到自定義相簿操作程式碼:

- (void)savePhtotsWithImage:(UIImage *)image {
    // 獲取當前的授權狀態
    PHAuthorizationStatus lastStatus = [PHPhotoLibrary authorizationStatus];
    
    // 請求授權
    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
        //回到主執行緒
        dispatch_async(dispatch_get_main_queue(), ^{
            
            if(status == PHAuthorizationStatusDenied) {
                if (lastStatus == PHAuthorizationStatusNotDetermined) {
                    //說明,使用者之前沒有做決定,在彈出授權框中,選擇了拒絕
                    [[AppDelegate app] showErrorAndAutoHide:@"儲存失敗!"];
                    return;
                }
                // 說明,之前使用者選擇拒絕過,現在又點選儲存按鈕,說明想要使用該功能,需要提示使用者開啟授權
                [[AppDelegate app] showErrorAndAutoHide:@"失敗!請開啟 設定-隱私-照片 來進行設定"];
                
            } else if(status == PHAuthorizationStatusAuthorized) {
                //儲存圖片---呼叫上面封裝的方法
                [self saveImageToCustomAblumWithImage:image];
            } else if (status == PHAuthorizationStatusRestricted) {
                [[AppDelegate app] showErrorAndAutoHide:@"系統原因,無法訪問相簿!"];
            }
        });
    }];
}

注:專案中需要儲存圖片到自定義相簿(整合網上資源+自定義封裝)分享共同學習

相關文章