保存(获取)图片到(自定义)相册


最近在学 iOS相关技术(绘图篇实现画板功能)的时候设计到了两个常用的知识点,那就是保存图片到相册和葱相册中获取图片。

只是个人比较好奇拓展一些技术,说的难听点叫做装牛角尖,好听点就是为了装逼而已,所以在保存相册的时候使用真及测试发现不能保存到我iPhone里 main的自定义相册里面,就查看文档和资料,也借鉴别人的分享实现了想要的功能,就把他给记录下来,这个虽然没有直接保存和获取常用但是也是一项很好的实用技术

一:首先来看看怎么获取相册的图片:

1     // 弹出系统的相册
 2     // 选择控制器(系统相册)
 3     UIImagePickerController *picekerVc = [[UIImagePickerController alloc] init];
 4     
 5     // 设置选择控制器的来源
 6     // UIImagePickerControllerSourceTypePhotoLibrary 相册集
 7     // UIImagePickerControllerSourceTypeSavedPhotosAlbum:照片库
 8     picekerVc.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
 9     
10     // 设置代理
11     picekerVc.delegate = self;
12     
13     // modal
14     [self presentViewController:picekerVc animated:YES completion:nil];

实现代理方法:

1 #pragma mark - UIImagePickerControllerDelegate
 2 // 当用户选择一张图片的时候调用
 3 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
 4 {
 5     // 获取选中的照片
 6     UIImage *image = info[UIImagePickerControllerOriginalImage];
 7 
 8     // 把选中的照片画到画板上
 9     
10     _drawView.image = image;
11     
12     // dismiss
13     [self dismissViewControllerAnimated:YES completion:nil];
14 }

注意:这里需要遵守两个协议:

<UINavigationControllerDelegate,UIImagePickerControllerDelegate>

关于只有UIImagePickerController却要遵守两个协议笔者也还在寻找答案,不过根据名字这个肯定是跟导航控制器有关,但是这设计到了底层的东西,这里就不多做解释了。

二:然后就是证明保存图片到系统的相册:

1     // 截屏
 2     // 开启上下文
 3     UIGraphicsBeginImageContextWithOptions(_drawView.bounds.size, NO, 0);
 4     
 5     // 获取上下文
 6     CGContextRef ctx = UIGraphicsGetCurrentContext();
 7     
 8     // 渲染图层
 9     [_drawView.layer renderInContext:ctx];
10     
11     // 获取上下文中的图片
12     UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
13     
14     // 关闭上下文
15     UIGraphicsEndImageContext();
16     
17     
18     // 保存画板的内容放入相册
19     // image:写入的图片
20     // completionTarget图片保存监听者
21     // 注意:以后写入相册方法中,想要监听图片有没有保存完成,保存完成的方法不能随意乱写
22     UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);

这里涉及到了图层的知识Quartz2d绘图,关于图层情查看笔者之前写的文章。

这里同样需要监听一下保存是否成功:

1 // 监听保存完成,必须实现这个方法
2 - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
3 {
4      NSLog(@"保存图片成功");
5 }

三:最后就是保存图片到我们在iphone中自定义相册:

保存照片还可以用ALAssetsLibraryALAssetsLibrary提供了我们对iOS设备中的相片、视频的访问,是连接应用程序和相册之间访问的一个桥梁。

接下来,我们来详细讲解一下关于系统相册权限获取、保存照片、创建自己的相簿等等功能。

创建自己的相簿

这也是一种比较创建的作法,创建自己的相簿,然后把照片或者视频保存到自己的相簿中。相关代码如下:

1   ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
2 [library addAssetsGroupAlbumWithName:@"test" resultBlock:^(ALAssetsGroup *group) {
3 
4     //创建相簿成功
5 
6 } failureBlock:^(NSError *error) {
7     //失败
8 }];

保存照片

这个方法也是将照片保存到系统相簿里面,不是保存到自己创建的相簿里面。代码如下:

1  ALAssetsLibrary *library = [[ALAssetsLibrary alloc]init];
 2 [library writeImageToSavedPhotosAlbum:image.CGImage orientation:(ALAssetOrientation)image.imageOrientation completionBlock:^(NSURL *asSetUrl,NSError *error){
 3     if (error) {
 4        //失败
 5     }else{
 6         UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"存储成功"
 7                                                        message:nil
 8                                                       delegate:nil
 9                                              cancelButtonTitle:@"确定"
10                                              otherButtonTitles:nil, nil];
11         [alert show];
12 
13     }
14 }];

获取权限

在保存照片之前,如果用户关闭相册权限,这个时候是保存失败的。如果你不做任何处理,用户是不会知道自己保存失败了。所以,我们可以在保存照片之前,做出相应的提示。如何获取这个权限呢?一般有两种方法:

  1. 创建相簿失败

  2. 保存照片失败

在上面两个方法创建自己的相簿保存照片的失败结果里,我们可以弹出获取照片权限失败的提示。我们拿第一个创建相簿失败来举例:

1 ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
 2 [library addAssetsGroupAlbumWithName:@"test" resultBlock:^(ALAssetsGroup *group)     {
 3 
 4       //创建相簿成功
 5 
 6 } failureBlock:^(NSError *error) {
 7       UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"存储失败"
 8                                                        message:@"请打开 设置-隐私-照片 来进行设置"
 9                                                       delegate:nil
10                                              cancelButtonTitle:@"确定"
11                                              otherButtonTitles:nil, nil];
12     [alert show];
13 }];

在保存照片失败的结果里,我们也可以弹出相应的提示,让用户打开应用程序的相册权限。

保存照片到自己的相簿

下面这段代码是在大谷歌里面找到的,亲自测试过是可以用的,整理如下:

1 #pragma mark - 创建相册
  2 - (void)createAlbum
  3 {
  4     ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];
  5     NSMutableArray *groups=[[NSMutableArray alloc]init];
  6     ALAssetsLibraryGroupsEnumerationResultsBlock listGroupBlock = ^(ALAssetsGroup *group, BOOL *stop)
  7     {
  8         if (group)
  9         {
 10             [groups addObject:group];
 11         }
 12 
 13         else
 14         {
 15             BOOL haveHDRGroup = NO;
 16 
 17             for (ALAssetsGroup *gp in groups)
 18             {
 19                 NSString *name =[gp valueForProperty:ALAssetsGroupPropertyName];
 20 
 21                 if ([name isEqualToString:@"iOSDevTip"])
 22                 {
 23                     haveHDRGroup = YES;
 24                 }
 25             }
 26 
 27             if (!haveHDRGroup)
 28             {
 29                 //do add a group named "XXXX"
 30                 [assetsLibrary addAssetsGroupAlbumWithName:@"iOSDevTip"
 31                                                resultBlock:^(ALAssetsGroup *group)
 32                  {
 33                      [groups addObject:group];
 34 
 35                  }
 36                                               failureBlock:nil];
 37                 haveHDRGroup = YES;
 38             }
 39         }
 40 
 41     };
 42     //创建相簿
 43     [assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAlbum usingBlock:listGroupBlock failureBlock:nil];
 44 
 45     [self saveToAlbumWithMetadata:nil imageData:UIImagePNGRepresentation(self.image) customAlbumName:@"iOSDevTip" completionBlock:^
 46      {
 47          //这里可以创建添加成功的方法
 48 
 49      }
 50                      failureBlock:^(NSError *error)
 51      {
 52          //处理添加失败的方法显示alert让它回到主线程执行,不然那个框框死活不肯弹出来
 53          dispatch_async(dispatch_get_main_queue(), ^{
 54 
 55              //添加失败一般是由用户不允许应用访问相册造成的,这边可以取出这种情况加以判断一下
 56              if([error.localizedDescription rangeOfString:@"User denied access"].location != NSNotFound ||[error.localizedDescription rangeOfString:@"用户拒绝访问"].location!=NSNotFound){
 57                  UIAlertView *alert=[[UIAlertView alloc]initWithTitle:error.localizedDescription message:error.localizedFailureReason delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", nil) otherButtonTitles: nil];
 58 
 59                  [alert show];
 60              }
 61          });
 62      }];
 63 }
 64 
 65 - (void)saveToAlbumWithMetadata:(NSDictionary *)metadata
 66                       imageData:(NSData *)imageData
 67                 customAlbumName:(NSString *)customAlbumName
 68                 completionBlock:(void (^)(void))completionBlock
 69                    failureBlock:(void (^)(NSError *error))failureBlock
 70 {
 71 
 72     ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];
 73     __weak ALAssetsLibrary *weakSelf = assetsLibrary;
 74     void (^AddAsset)(ALAssetsLibrary *, NSURL *) = ^(ALAssetsLibrary *assetsLibrary, NSURL *assetURL) {
 75         [assetsLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) {
 76             [assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
 77 
 78                 if ([[group valueForProperty:ALAssetsGroupPropertyName] isEqualToString:customAlbumName]) {
 79                     [group addAsset:asset];
 80                     if (completionBlock) {
 81                         completionBlock();
 82                     }
 83                 }
 84             } failureBlock:^(NSError *error) {
 85                 if (failureBlock) {
 86                     failureBlock(error);
 87                 }
 88             }];
 89         } failureBlock:^(NSError *error) {
 90             if (failureBlock) {
 91                 failureBlock(error);
 92             }
 93         }];
 94     };
 95     [assetsLibrary writeImageDataToSavedPhotosAlbum:imageData metadata:metadata completionBlock:^(NSURL *assetURL, NSError *error) {
 96         if (customAlbumName) {
 97             [assetsLibrary addAssetsGroupAlbumWithName:customAlbumName resultBlock:^(ALAssetsGroup *group) {
 98                 if (group) {
 99                     [weakSelf assetForURL:assetURL resultBlock:^(ALAsset *asset) {
100                         [group addAsset:asset];
101                         if (completionBlock) {
102                             completionBlock();
103                         }
104                     } failureBlock:^(NSError *error) {
105                         if (failureBlock) {
106                             failureBlock(error);
107                         }
108                     }];
109                 } else {
110                     AddAsset(weakSelf, assetURL);
111                 }
112             } failureBlock:^(NSError *error) {
113                 AddAsset(weakSelf, assetURL);
114             }];
115         } else {
116             if (completionBlock) {
117                 completionBlock();
118             }
119         }
120     }];
121 }

ALAssetsLibrary+CustomPhotoAlbum保存照片

github上有一个项目ALAssetsLibrary+CustomPhotoAlbum :(https://github.com/Kjuly/ALAssetsLibrary-CustomPhotoAlbum ),讲保存照片做了很好的封装。使用之前记得先导入头文件:

#import "ALAssetsLibrary+CustomPhotoAlbum.h"

保存照片到自己的相簿,直接调用:

1 ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
2 [library saveImage:self.image toAlbum:@"gang" completion:^(NSURL *assetURL, NSError *error) {
3     if (!error) {
4 
5     }
6 } failure:^(NSError *error) {
7 
8 }];

ALAssetsLibrary+CustomPhotoAlbum对保存视频的封装也是非常好的。我现在项目中用的也是这个第三方来保存照片和视频。因为不错,所以推荐给大家使用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章