iOS 保存圖片到【自定義相冊(cè)】

一、保存圖片到自定義相冊(cè)的三個(gè)步驟

  • 1.保存圖片到相冊(cè)【相機(jī)膠卷】
    1>、C語(yǔ)言保存
    2>、#import <AssetsLibrary/AssetsLibrary.h> 保存

    AssetsLibrary框架: iOS9 之后開(kāi)始被廢棄

    3>、#import <Photos/Photos.h> 保存

    Photos框架 iOS 8 開(kāi)始就可以用了

  • 2.擁有一個(gè)自定義相冊(cè):使用AssetsLibraryPhotos框架

  • 3.將剛才保存到【相機(jī)膠卷中的圖片】引用到【自定義的相冊(cè)】:使用AssetsLibraryPhotos框架

二、單純的C語(yǔ)言保存圖片到相冊(cè)(不使用AssetsLibraryPhotos框架)

  • 2.1、保存圖片到相冊(cè)

    /**
     <#Description#>
    
      第1個(gè)參數(shù):UIIMage 對(duì)象
      第2個(gè)參數(shù):監(jiān)聽(tīng)對(duì)象
      第3個(gè)參數(shù):保存后所走【監(jiān)聽(tīng)對(duì)象】的方法
      第4個(gè)參數(shù):描述文字,一般為 niul
    */
    UIImageWriteToSavedPhotosAlbum(self.photoimageView.image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
    
    #pragma mark 保存成功后所走的方法
    - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{
    
         // 保存完畢
         if (error) {
      
            NSLog(@"保存失敗");
         }else{
      
            NSLog(@"保存成功");
         }
    }
    

    提示:上面第三個(gè)參數(shù)是要按照蘋(píng)果的格式來(lái)寫(xiě)方法名的,點(diǎn)擊方法進(jìn)去 我們可以到如下代碼:
    // Adds a photo to the saved photos album. The optional completionSelector should have the form:
    // - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo;
    蘋(píng)果讓我們按照他們的格式來(lái)寫(xiě)方法,我們可以把他們的方法名替換為任意的名字,如:

    - (void)a:(UIImage *)image b:(NSError *)error c:(void *)contextInfo;
    

三、Photos 框架

  • 3.1、Photos 框架基本認(rèn)識(shí),我們可以在 Help->Developer Documentation-> 選擇OC或者Swift 搜索 Photos

    Photos 框架檢索

    Photos 是用來(lái)處理 視頻 與 圖片 的,下面是其主要的類(lèi)

    • <1>、PHAsset:一個(gè) PHAsset 對(duì)象就代表相冊(cè)中的一張圖片或者一個(gè)視頻

      (1)、查:[PHAsset fetch.....]
      (2)、增刪改:PHAssetChangeRequest,改變圖片 (包括 圖片/視頻 相關(guān)的所有改動(dòng)操作)

    • <2>、:PHAssetCollection: 一個(gè)PHAssetCollection就代表一個(gè)相冊(cè)
      (1)、查:[PHAssetCollection fetch.....]
      (2)、增刪改:PHAssetCollectionChangeRequest,改變相冊(cè) (包括 相冊(cè) 相關(guān)的所有改動(dòng)操作)

    提示:所有的增刪改的操作都要放到:-[PHPhotoLibrary performChanges:completionHandler:] or -[PHPhotoLibrary performChangesAndWait:error:]'方法里面

  • 3.2、使用 Photos 框架保存圖片到【相機(jī)膠卷】

    • 異步操作保存到相冊(cè)

      [[PHPhotoLibrary sharedPhotoLibrary]performChanges:^{
      
           [PHAssetChangeRequest creationRequestForAssetFromImage:self.photoimageView.image];
      
      } completionHandler:^(BOOL success, NSError * _Nullable error) {
      
           if (error) {
                [SVProgressHUD showErrorWithStatus:@"保存失敗"];
           }else{
                [SVProgressHUD showErrorWithStatus:@"保存成功"];
          }
      }];
      
    • 同步操作保存到相冊(cè)

      NSError *error = nil;
      
      [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
      
         [PHAssetChangeRequest creationRequestForAssetFromImage:self.photoimageView.image];
      
      } error:&error];
      
      if (error) {
          [SVProgressHUD showErrorWithStatus:@"保存失敗"];
      }else{
          [SVProgressHUD showErrorWithStatus:@"保存成功"];
      }
      

    提示:使用 Photos 框架保存圖片到【相機(jī)膠卷】必須把代碼放到上面的兩個(gè)方法里面,否則會(huì)報(bào)下面的錯(cuò)
    reason: 'This method can only be called from inside of -[PHPhotoLibrary performChanges:completionHandler:] or -[PHPhotoLibrary performChangesAndWait:error:]'

  • 3.3、創(chuàng)建新的相冊(cè)(自定義一個(gè)屬于自己app的相冊(cè)),提示:創(chuàng)建相冊(cè)之前要先判斷相冊(cè)是否存在,存在就不再創(chuàng)建

    NSError *error = nil;
    
    [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
      
         // 獲取app的名字
         NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
         // 創(chuàng)建一個(gè)自定義的相冊(cè) 
         [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle: appName];
      
     } error:&error];
    
     if (error) {
            [SVProgressHUD showErrorWithStatus:@"創(chuàng)建相冊(cè)失敗"];
     }else{
            [SVProgressHUD showErrorWithStatus:@"創(chuàng)建相冊(cè)成功"];
     }
    

    提示一kCFBundleNameKey = @"CFBundleName",下面的兩句是一個(gè)意思

    • NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
      下面是:C 的strting轉(zhuǎn)為NSString
    • NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleNameKey];

    提示二:Foundation 和 Core Foundation 的數(shù)據(jù)類(lèi)型可以相互轉(zhuǎn)換,比如:NSString * 和 CFStringRef,如下面的例子:

    NSString *string = (NSString *)kCFBundleNameKey;
    CFStringRef string = (CFStringRef)@"name";
    
  • 3.4、查詢(xún)相冊(cè) (自定義相冊(cè)或者系統(tǒng)相冊(cè))

    /**
      PHAssetCollectionTypeAlbum      = 1, 自定義相冊(cè)(普通的相冊(cè))
      PHAssetCollectionTypeSmartAlbum = 2, 智能相冊(cè)(系統(tǒng)自帶的相冊(cè)),如:Camera Roll
      PHAssetCollectionTypeMoment     = 3, 按照時(shí)刻分的相冊(cè)
     */
    
    // 相機(jī)膠卷相冊(cè),打?。篊amera Roll
    // PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil];
    // 自定義相冊(cè),打?。鹤远x相冊(cè)的名字
    PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    for (PHAssetCollection *collection in collections) {
      
      NSLog(@"相冊(cè)的名字=%@",collection.localizedTitle);
    }
    
  • 3.5.創(chuàng)建相冊(cè)與查詢(xún)相冊(cè)合在一起,如下

    // 獲取app的名字
    NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
    
    /**
      PHAssetCollectionTypeAlbum      = 1, 自定義相冊(cè)(普通的相冊(cè))
      PHAssetCollectionTypeSmartAlbum = 2, 智能相冊(cè)(系統(tǒng)自帶的相冊(cè)),如:Camera Roll
      PHAssetCollectionTypeMoment     = 3, 按照時(shí)刻分的相冊(cè)
     */
    
     // 相機(jī)膠卷相冊(cè),打印:Camera Roll
     // PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil];
     // 自定義相冊(cè),打印:自定義相冊(cè)的名字
     PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    
     // 自己的相冊(cè)
     PHAssetCollection *appCollection = nil;
    
     for (PHAssetCollection *collection in collections) {
      
        NSLog(@"相冊(cè)的名字=%@",collection.localizedTitle);
      
        if ([collection.localizedTitle isEqualToString:appName]) {
          
             appCollection = collection;
             break;
        }
     }
    
     if (appCollection == nil) {
      
         NSError *error = nil;
      
         __block NSString *createCollectionID = nil;
      
         [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
          
             // 獲取app的名字
             NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
             // 獲取相冊(cè)的唯一標(biāo)識(shí)符
             createCollectionID = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:appName].placeholderForCreatedAssetCollection.localIdentifier;
          
          } error:&error];
      
          if (error) {
              [SVProgressHUD showErrorWithStatus:@"創(chuàng)建相冊(cè)失敗"];
          }else{
          
              appCollection = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[createCollectionID] options:nil].firstObject;
              [SVProgressHUD showErrorWithStatus:@"創(chuàng)建相冊(cè)成功"];
          }
      }
    
      // 相冊(cè)一定存在
      NSLog(@"相冊(cè)已經(jīng)存在");
    

    提示:這里有一個(gè)技術(shù)點(diǎn)就是:根據(jù)創(chuàng)建相冊(cè)返回的相冊(cè)唯一標(biāo)識(shí)符獲取相冊(cè)對(duì)象,如下代碼:

    // 自己的相冊(cè)
    PHAssetCollection *appCollection = nil;
    if (appCollection == nil) {
    
        NSError *error = nil;
    
        __block NSString *createCollectionID = nil;
    
        [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
    
            // 獲取app的名字
            NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
            // 獲取相冊(cè)的唯一標(biāo)識(shí)符
            createCollectionID = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:appName].placeholderForCreatedAssetCollection.localIdentifier;
    
         } error:&error];
    
         if (error) {
            [SVProgressHUD showErrorWithStatus:@"創(chuàng)建相冊(cè)失敗"];
         }else{
            appCollection = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[createCollectionID] options:nil].firstObject;
            [SVProgressHUD showErrorWithStatus:@"創(chuàng)建相冊(cè)成功"];
         }
     }
    
    • 再次提示:只有上面的block代碼執(zhí)行完才代表相冊(cè)可能存在,所以,獲取PHAssetCollection放在了下面
  • 3.6、保存圖片到自定義的相冊(cè)

    -(void)savePhotosToAppPhotoCollection{
    
       // 同步操作保存到【相機(jī)膠卷】
       __block PHObjectPlaceholder *placeholderForCreatedAsset;
       NSError *error = nil;
       [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
      
            placeholderForCreatedAsset = [PHAssetChangeRequest creationRequestForAssetFromImage:self.photoimageView.image].placeholderForCreatedAsset;
      
         } error:&error];
    
         if (error) {
             [SVProgressHUD showErrorWithStatus:@"保存圖片失敗"];
             return;
         }
    
         // 獲得自定義相冊(cè)
         PHAssetCollection *createCollection = [JKPhotosKit createPHAssetCollection];
         if (createCollection == nil) {
              [SVProgressHUD showErrorWithStatus:@"創(chuàng)建相冊(cè)失敗"];
              return;
         }
    
         // 添加剛才保存的圖片到 【自定義相冊(cè)】
         [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
              // 獲取自定義對(duì)象的操作對(duì)象
              PHAssetCollectionChangeRequest *request = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:createCollection];
              // 把圖片插入到自定義相冊(cè)的第一個(gè)位置
              [request insertAssets:@[placeholderForCreatedAsset] atIndexes:[NSIndexSet indexSetWithIndex:0]];
      
          } error:&error];
    
          if (error) {
              [SVProgressHUD showErrorWithStatus:@"保存圖片失敗"];
          }else{
              [SVProgressHUD showSuccessWithStatus:@"保存圖片成功"];
          }
    }
    
  • 3.7、用戶(hù)相冊(cè)權(quán)限的判斷

    // 請(qǐng)求或者訪(fǎng)問(wèn)用戶(hù)訪(fǎng)問(wèn)權(quán)限:
    // 如果還沒(méi)有做出選擇,會(huì)自動(dòng)彈框,用戶(hù)對(duì)彈框做出選擇后才會(huì)調(diào)用block;
    // 如果用戶(hù)之前已經(jīng)做出過(guò)選擇,會(huì)自動(dòng)執(zhí)行block
    /**
      PHAuthorizationStatusNotDetermined = 0,還沒(méi)決定
      PHAuthorizationStatusRestricted = 1,沒(méi)有授權(quán),不能訪(fǎng)問(wèn)用戶(hù)相冊(cè)
      PHAuthorizationStatusDenied = 2,用戶(hù)拒絕這個(gè)應(yīng)用
      PHAuthorizationStatusAuthorized = 3 用戶(hù)授權(quán)這個(gè)app訪(fǎng)問(wèn)這個(gè)相冊(cè)
     */
    // 獲取用戶(hù)之前的狀態(tài)
    PHAuthorizationStatus oldStatus = [PHPhotoLibrary authorizationStatus];
    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
    
      // 用戶(hù)決絕當(dāng)前 App 訪(fǎng)問(wèn)相冊(cè)
      dispatch_async(dispatch_get_main_queue(), ^{
          
          if (status == PHAuthorizationStatusDenied) {
             
              if (oldStatus != PHAuthorizationStatusDenied) {
                  
                  // 提醒用戶(hù)打開(kāi)開(kāi)關(guān)
                  
              }else{
                  
              }
              
          }else if (status == PHAuthorizationStatusAuthorized){
              // 用戶(hù)允許當(dāng)前 App 訪(fǎng)問(wèn)相冊(cè)
              [self trueSaveImageToAppPhotoCollection:saveImage];
              
          }else if (status == PHAuthorizationStatusRestricted){
              // 因系統(tǒng)原因無(wú)法訪(fǎng)問(wèn)相冊(cè)
              [SVProgressHUD showErrorWithStatus:@"因系統(tǒng)原因無(wú)法訪(fǎng)問(wèn)相冊(cè)"];
          }
      });
    }];
    

    提示:上面所有的完整代碼都在 JKPhotosKit類(lèi)里面,需要的請(qǐng)下載 demo

    • JKPhotosKit 類(lèi)的使用方法:保存圖片到自定的相冊(cè)
      [JKPhotosKit savePhotosToAppPhotoCollection:UIImage對(duì)象];
      效果圖

完整代碼都在 JKPhotosKit類(lèi)里面,需要的請(qǐng)下載 demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容