iOS-保存圖片到自定義相冊(cè)|Photos|C函數(shù)

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

<b style="color:red">
實(shí)際上,自定義相冊(cè)中的圖片并不是實(shí)際的圖片迅涮,而是對(duì)系統(tǒng)【相機(jī)膠卷】這個(gè)相冊(cè)中的圖片進(jìn)行了一個(gè)引用。所以將圖片保存到自定義相冊(cè)的第一步就是先保存到系統(tǒng)的【相機(jī)膠卷】中。
</b>

1 步驟

  • 保存到系統(tǒng)的相冊(cè)【相機(jī)膠卷】中

      (1)C語(yǔ)言函數(shù)來(lái)保存
      (2)AssetsLibrary框架--系統(tǒng)自帶舟扎,iOS9廢棄
      (3)Photos框架--系統(tǒng)自帶遥巴,iOS8即可使用千康,取代AssetsLibrary
    
  • 擁有自定義相冊(cè)(如果沒(méi)有,則創(chuàng)建)

      AssetsLibrary
      Photos
    
  • 將圖片添加到自定義相冊(cè)中

      AssetsLibrary
      Photos
    

2 Photos 框架簡(jiǎn)單介紹

2.1 重要的類(lèi)

該框架有幾個(gè)非常重要的類(lèi):PHAsset铲掐、PHAssetCollection 和 PHLibrary拾弃。

  • PHAsset 表示一個(gè)圖片或者視頻文件(存儲(chǔ)在手機(jī)的照片 APP 中的)。與具體圖片有關(guān)的使用這個(gè)類(lèi)
  • PHAssetCollection 表示圖片集合或者視頻集合摆霉,其實(shí)就是指相冊(cè)(包括系統(tǒng)相冊(cè)和自定義相冊(cè))
  • PHLibrary 表示整個(gè)相冊(cè)庫(kù)豪椿,包括整個(gè)相冊(cè)和圖片等

<b style="color:red">
只要與單個(gè)圖片相關(guān),使用 PHAsset携栋。只要與相冊(cè)相關(guān)搭盾,使用 PHAssetCollection
</b>

2.2 查詢(xún)操作

查詢(xún)操作,直接使用 PHAsset 和 PHAssetCollection 類(lèi)本身的方法

//1 獲取相冊(cè)中的圖片--傳入相冊(cè)圖片的 ID---返回一組圖片
[PHAsset fetchAssetsWithLocalIdentifiers:@[ID] options:nil];

//2 查詢(xún)手機(jī)中所有的相冊(cè)列表(分為系統(tǒng)相冊(cè)和自定義相冊(cè)婉支,通過(guò)控制傳入的參數(shù)來(lái)確定)---返回相冊(cè)組--類(lèi)似數(shù)組-forin遍歷即可
[PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
2.3 增刪改操作(除了獲取之外所有的操作)

<b style="color:red">
1 如果做查詢(xún)之外的操作鸯隅,比如說(shuō)保存圖片、創(chuàng)建自定義相冊(cè)向挖、向自定義相冊(cè)中添加圖片等蝌以,都需要使用另外兩個(gè)類(lèi):PHAssetChangeRequest 和 PHAssetCollectionChangeRequest

2 這些操作必須在 [[PHPhotoLibrary sharedPhotoLibrary]performChange...]的 block 中間調(diào)用

</b>

//1 保存圖片
[PHAssetChangeRequest creationRequestForAssetFromImage:self.imageView.image];

//2 創(chuàng)建相冊(cè)
[PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:@"自定義相冊(cè)"];   

3 將圖片保存到系統(tǒng)相冊(cè)【相機(jī)膠卷】中

3.1 C語(yǔ)言函數(shù)保存

點(diǎn)擊保存按鈕后的代碼:

//1 把圖片保存到系統(tǒng)相冊(cè)中,結(jié)束后調(diào)用 image:didFinishSavingWithError:contextInfo:方法(回調(diào)方法)
//2 回調(diào)方法的格式有要求何之,可以進(jìn)入頭文件查看
UIImageWriteToSavedPhotosAlbum(self.imageView.image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);

實(shí)現(xiàn)回調(diào)方法

-(void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
    if(error)
    {
        NSLog(@"保存圖片失敗");
        return;
    }
    NSLog(@"保存圖片成功");
}
3.2 Photos 框架保存圖片到系統(tǒng)相冊(cè)

Photos 框架保存圖片 --- 使用 PHAssetChangeRequest 類(lèi) 方法

有兩種方式;異步方式和同步方式跟畅,但是保存圖片的操作性能消耗不大,所以可以直接使用同步方式

3.2.1 異步方式保存圖片
//異步保存圖片
-(void)asyncSaveImageWithPhotos
{
    //1 必須在 block 中調(diào)用
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        //2 異步執(zhí)行保存圖片操作
        [PHAssetChangeRequest creationRequestForAssetFromImage:self.imageView.image];

    } completionHandler:^(BOOL success, NSError * _Nullable error) {
        //3 保存結(jié)束后帝美,回調(diào)
        if (error) {
            [SVProgressHUD showErrorWithStatus:@"保存失敗"];
        }else
            [SVProgressHUD showSuccessWithStatus:@"保存成功"];
    }];
}

#######3.2.2 同步方式保存圖片

下面的例子是通過(guò)保存時(shí)刻的占位 id 來(lái)獲取圖像碍彭,其實(shí)也可以直接返回占位圖片晤硕。后面的操作可以直接進(jìn)使用占位圖片代替圖片

/**同步方式保存圖片到系統(tǒng)的相機(jī)膠卷中---返回的是當(dāng)前保存成功后相冊(cè)圖片對(duì)象集合*/
-(PHFetchResult<PHAsset *> *)syncSaveImageWithPhotos
{
    //--1 創(chuàng)建 ID 這個(gè)參數(shù)可以獲取到圖片保存后的 asset對(duì)象
    __block NSString *createdAssetID = nil;

    //--2 保存圖片
    NSError *error = nil;
    [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
        //----block 執(zhí)行的時(shí)候還沒(méi)有保存成功--獲取占位圖片的 id,通過(guò) id 獲取圖片---同步
        createdAssetID = [PHAssetChangeRequest          creationRequestForAssetFromImage:self.imageView.image].placeholderForCreatedAsset.localIdentifier;
    } error:&error];

    //--3 如果失敗庇忌,則返回空
    if (error) {
        return nil;
    }

    //--4 成功后舞箍,返回對(duì)象
    //獲取保存到系統(tǒng)相冊(cè)成功后的 asset 對(duì)象集合,并返回
    PHFetchResult<PHAsset *> *assets = [PHAsset fetchAssetsWithLocalIdentifiers:@[createdAssetID] options:nil];
    return assets;

}

4 擁有自定義相冊(cè)(如果沒(méi)有皆疹,則創(chuàng)建)

下面的例子是:如果沒(méi)有疏橄,則常見(jiàn)跟當(dāng)前 APP 同名的自定義相冊(cè)

實(shí)現(xiàn)思路:

① 獲取當(dāng)前的 APP 的 BundleName

② 使用PHAssetCollection的fetchAssetCollectionsWithType:subType:options方法,通過(guò)傳入類(lèi)型略就,獲取所有的自定義相冊(cè)列表

③ 遍歷獲取的自定義相冊(cè)列表捎迫,與APP的名稱(chēng)進(jìn)行比對(duì),匹配后返回當(dāng)前同名的自定義相冊(cè) PHAssetCollection對(duì)象

④ 如果沒(méi)有找到表牢,則開(kāi)始創(chuàng)建窄绒,在PHPhotoLibrary單例對(duì)象的perfromChange方法中執(zhí)行創(chuàng)建自定義相冊(cè)操作

⑤ block中,保存待創(chuàng)建相冊(cè)的占位標(biāo)識(shí)符---其實(shí)這個(gè)時(shí)刻崔兴,相冊(cè)根本沒(méi)創(chuàng)建完成

⑥ 通過(guò)error判斷是否創(chuàng)建成功彰导,

⑦ 如果創(chuàng)建成功,通過(guò)PHAssetCollection的fetchAssetCollectionsWithLocalIdentifiers:options來(lái)獲取當(dāng)前創(chuàng)建相冊(cè)對(duì)象PHAssetCollection

/**擁有與 APP 同名的自定義相冊(cè)--如果沒(méi)有則創(chuàng)建*/
-(PHAssetCollection *)getAssetCollectionWithAppNameAndCreateIfNo
{
    //1 獲取以 APP 的名稱(chēng)
    NSString *title = [NSBundle mainBundle].infoDictionary[(__bridge NSString *)kCFBundleNameKey];
    //2 獲取與 APP 同名的自定義相冊(cè)
    PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    for (PHAssetCollection *collection in collections) {
        //遍歷
        if ([collection.localizedTitle isEqualToString:title]) {
            //找到了同名的自定義相冊(cè)--返回
            return collection;
        }
    }

    //說(shuō)明沒(méi)有找到敲茄,需要?jiǎng)?chuàng)建
    NSError *error = nil;
    __block NSString *createID = nil; //用來(lái)獲取創(chuàng)建好的相冊(cè)
    [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
        //發(fā)起了創(chuàng)建新相冊(cè)的請(qǐng)求位谋,并拿到ID,當(dāng)前并沒(méi)有創(chuàng)建成功堰燎,待創(chuàng)建成功后掏父,通過(guò) ID 來(lái)獲取創(chuàng)建好的自定義相冊(cè)
        PHAssetCollectionChangeRequest *request = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:title];
        createID = request.placeholderForCreatedAssetCollection.localIdentifier;
    } error:&error];
    if (error) {
        [SVProgressHUD showErrorWithStatus:@"創(chuàng)建失敗"];
        return nil;
    }else{
        [SVProgressHUD showSuccessWithStatus:@"創(chuàng)建成功"];
        //通過(guò) ID 獲取創(chuàng)建完成的相冊(cè) -- 是一個(gè)數(shù)組
        return [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[createID] options:nil].firstObject;
    }

}

5 將圖片對(duì)象添加到自定義相冊(cè)中

實(shí)現(xiàn)思路

① 使用獲取的自定義相冊(cè)來(lái)創(chuàng)建PHAssetCollection對(duì)象

② 將剛才保存到系統(tǒng)相冊(cè)的PHAsset保存到相冊(cè)中

/**將圖片保存到自定義相冊(cè)中*/
-(void)saveImageToCustomAblum
{
    //1 將圖片保存到系統(tǒng)的【相機(jī)膠卷】中---調(diào)用剛才的方法
    PHFetchResult<PHAsset *> *assets = [self syncSaveImageWithPhotos];
    if (assets == nil)
    {
        [SVProgressHUD showErrorWithStatus:@"保存失敗"];
        return;
    }

    //2 擁有自定義相冊(cè)(與 APP 同名,如果沒(méi)有則創(chuàng)建)--調(diào)用剛才的方法
    PHAssetCollection *assetCollection = [self getAssetCollectionWithAppNameAndCreateIfNo];
    if (assetCollection == nil) {
        [SVProgressHUD showErrorWithStatus:@"相冊(cè)創(chuàng)建失敗"];
        return;
    }


    //3 將剛才保存到相機(jī)膠卷的圖片添加到自定義相冊(cè)中 --- 保存帶自定義相冊(cè)--屬于增的操作秆剪,需要在PHPhotoLibrary的block中進(jìn)行
    NSError *error = nil;
    [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
        //--告訴系統(tǒng)赊淑,要操作哪個(gè)相冊(cè)
        PHAssetCollectionChangeRequest *collectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
        //--添加圖片到自定義相冊(cè)--追加--就不能成為封面了
        //--[collectionChangeRequest addAssets:assets];
        //--插入圖片到自定義相冊(cè)--插入--可以成為封面
        [collectionChangeRequest insertAssets:assets atIndexes:[NSIndexSet indexSetWithIndex:0]];
    } error:&error];
    
    
    if (error) {
        [SVProgressHUD showErrorWithStatus:@"保存失敗"];
        return;
    }
    [SVProgressHUD showSuccessWithStatus:@"保存成功"];
}

6 相冊(cè)的授權(quán)訪(fǎng)問(wèn)

當(dāng)?shù)谝淮问褂肁PP的時(shí)候,或者第一次訪(fǎng)問(wèn)相冊(cè)的時(shí)候鸟款,系統(tǒng)會(huì)彈出授權(quán)選擇對(duì)話(huà)框詢(xún)問(wèn)用戶(hù)膏燃。所以我們?cè)诒4鎴D片到相冊(cè)的時(shí)候,需要判斷當(dāng)前是否授權(quán)何什。

6.1 權(quán)限分類(lèi)
PHAuthorizationStatusNotDetermined ,---用戶(hù)之前還未決定
PHAuthorizationStatusRestricted, ---系統(tǒng)問(wèn)題组哩,用戶(hù)沒(méi)有權(quán)限決定--比如家長(zhǎng)控制器模式
PHAuthorizationStatusDenied,---用戶(hù)之前拒絕過(guò)
PHAuthorizationStatusAuthorized --用戶(hù)允許
6.2 請(qǐng)求權(quán)限的方式

可以使用NSPhotoLibrary的類(lèi)方法requestAuthorization來(lái)查看權(quán)限,或者請(qǐng)求權(quán)限处渣。如果用戶(hù)之前沒(méi)做決定伶贰,則彈出系統(tǒng)對(duì)話(huà)框請(qǐng)求權(quán)限;如果用戶(hù)做過(guò)決定罐栈,則調(diào)用該類(lèi)方法的block黍衙。

/*
 1 block 調(diào)用時(shí)刻---這個(gè)實(shí)在子線(xiàn)程中調(diào)用的
 --1.1 如果用戶(hù)第一次打開(kāi) APP,之前決定過(guò)權(quán)限荠诬,則彈出系統(tǒng)框琅翻,讓用戶(hù)選擇權(quán)限位仁。---選擇之后才會(huì)調(diào)用 block,并把剛才選擇的結(jié)果一并傳入
 --1.2 如果用戶(hù)之前已經(jīng)決定過(guò)權(quán)限方椎,則直接調(diào)用 block聂抢,并把之前選擇的結(jié)果傳入
 2 state 類(lèi)型
    PHAuthorizationStatusNotDetermined ,---用戶(hù)之前還未決定,直接彈出系統(tǒng)對(duì)話(huà)框棠众,這個(gè) state 不會(huì)傳給 block琳疏,會(huì)傳入用戶(hù)選擇的結(jié)果
    PHAuthorizationStatusRestricted, ---系統(tǒng)問(wèn)題,用戶(hù)沒(méi)有權(quán)限決定--比如家長(zhǎng)控制器模式
    PHAuthorizationStatusDenied,---用戶(hù)之前拒絕過(guò)
    PHAuthorizationStatusAuthorized --用戶(hù)允許闸拿,直接調(diào)用 block空盼,傳入該狀態(tài)
 **/

[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
    //當(dāng)前的block的調(diào)用是在子線(xiàn)程,需要回到主線(xiàn)程來(lái)操作
}
6.3 例子

點(diǎn)擊保存圖片按鈕后的操作---一個(gè)完整的將圖片保存到自定義相冊(cè)的操作

-(void)save
{
    //(1) 獲取當(dāng)前的授權(quán)狀態(tài)
    PHAuthorizationStatus lastStatus = [PHPhotoLibrary authorizationStatus];
    
    //(2) 請(qǐng)求授權(quán)
    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
        //回到主線(xiàn)程
        dispatch_async(dispatch_get_main_queue(), ^{
        
            if(status == PHAuthorizationStatusDenied) //用戶(hù)拒絕(可能是之前拒絕的新荤,有可能是剛才在系統(tǒng)彈框中選擇的拒絕)
            {
                if (lastStatus == PHAuthorizationStatusNotDetermined) {
                    //說(shuō)明揽趾,用戶(hù)之前沒(méi)有做決定,在彈出授權(quán)框中苛骨,選擇了拒絕
                    [SVProgressHUD showErrorWithStatus:@"保存失敗"];
                    return;
                }
                // 說(shuō)明但骨,之前用戶(hù)選擇拒絕過(guò),現(xiàn)在又點(diǎn)擊保存按鈕智袭,說(shuō)明想要使用該功能,需要提示用戶(hù)打開(kāi)授權(quán)
                [SVProgressHUD showInfoWithStatus:@"失斅犹А吼野!請(qǐng)?jiān)谙到y(tǒng)設(shè)置中開(kāi)啟訪(fǎng)問(wèn)相冊(cè)權(quán)限"];
            
            }
            else if(status == PHAuthorizationStatusAuthorized) //用戶(hù)允許
            {
                //保存圖片---調(diào)用上面封裝的方法
                [self saveImageToCustomAblum];
            }
            else if (status == PHAuthorizationStatusRestricted)
            {
                [SVProgressHUD showErrorWithStatus:@"系統(tǒng)原因,無(wú)法訪(fǎng)問(wèn)相冊(cè)"];
            }
        });
    }];
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末两波,一起剝皮案震驚了整個(gè)濱河市瞳步,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌腰奋,老刑警劉巖单起,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異劣坊,居然都是意外死亡嘀倒,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)局冰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)测蘑,“玉大人,你說(shuō)我怎么就攤上這事康二√几欤” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵沫勿,是天一觀的道長(zhǎng)挨约。 經(jīng)常有香客問(wèn)我味混,道長(zhǎng),這世上最難降的妖魔是什么诫惭? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任翁锡,我火速辦了婚禮,結(jié)果婚禮上贝攒,老公的妹妹穿的比我還像新娘盗誊。我一直安慰自己,他們只是感情好隘弊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布哈踱。 她就那樣靜靜地躺著,像睡著了一般梨熙。 火紅的嫁衣襯著肌膚如雪开镣。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天咽扇,我揣著相機(jī)與錄音邪财,去河邊找鬼。 笑死质欲,一個(gè)胖子當(dāng)著我的面吹牛树埠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嘶伟,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼怎憋,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了九昧?” 一聲冷哼從身側(cè)響起绊袋,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎铸鹰,沒(méi)想到半個(gè)月后癌别,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蹋笼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年展姐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姓建。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡诞仓,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出速兔,到底是詐尸還是另有隱情墅拭,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布涣狗,位于F島的核電站谍婉,受9級(jí)特大地震影響舒憾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜穗熬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一镀迂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧唤蔗,春花似錦探遵、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至棍掐,卻和暖如春藏雏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背作煌。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工掘殴, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人粟誓。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓奏寨,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親鹰服。 傳聞我的和親對(duì)象是個(gè)殘疾皇子服爷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

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