问题

iOS-对图片操作---添加到自定义相册

2018-09-11  本文已影响673人  蒋大为

图片操作---添加到自定义相册

实际上,自定义相册中的图片并不是实际的图片,而是对系统【相机胶卷】这个相册中的图片进行一个引用,所以将图片保存到自定义相册的第一步就是先保存到系统的【相机胶卷】中...

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:@"系统原因,无法访问相册!"];
            }
        });
    }];
}

注:项目中需要保存图片到自定义相册(整合网上资源+自定义封装)分享共同学习

上一篇下一篇

猜你喜欢

热点阅读