图片保存到相册和取一张或多张照片

本文介绍如何在iOS应用中将图片保存到系统相册或自定义相册,并提供了使用Photos框架实现的具体代码示例。此外,还介绍了如何通过UIImagePickerController等组件从系统相册中选取一张或多张图片。

一: 把软件中的图片保存到系统相册或者保存到自己创建的相册中

方式一:
demo:

保存图片到系统相册,这只是简单的把图片保存到系统相册中

传入博客的参考图片加载不出来,请参考OnlyChenJ的简书


Snip20160416_8.png
方式二:

保存图片到相册指定相册里,注意:其实只是把Camera Roll的相片又引用到了新的相册里
因为无论什么图片,都会首先保存在Camera Roll这个相册,之后根据自己的设置,才会保存
在指定的相册中

  • 1>思路:

Snip20160416_9.png
  • 2>思路步骤 :

    • 1.添加图片到【相机胶卷】
      1>UIImageWriteToSavedPhotosAlbum函数
      2> AssetsLibrary框架
      3>Photos框架(推荐)

    • 2.拥有一个【自定义相册】
      1> AssetsLibrary框架
      2> Photos框架(推荐)

    • 3.将刚才添加到【相机胶卷】的图片,引用(添加)到【自定义相册】
      1> AssetsLibrary框架
      2> Photos框架(推荐)

  • 3>需要用到的框架,主要还是用到Photos框架,也是苹果自带的框架

    • Photos框架须知

      • 1.PHAsset : 一个PHAsset对象代表一张图片或者一个视频文件
        1> 负责查询一堆的PHAsset对象

      • 2.PHAssetCollection : 一个PHAssetCollection对象代表一个相册
        1> 负责查询一堆的PHAssetCollection对象

      • 3.PHAssetChangeRequest
        1> 负责执行对PHAsset的【增删改】操作
        2> 这个类只能放在
        -[PHPhotoLibrary performChanges:completionHandler:]或者
        -[PHPhotoLibrary performChangesAndWait:error:]方法的block中使用

      • 4.PHAssetCollectionChangeRequest
        1> 负责执行对PHAssetCollection的【增删改】操作
        2> 这个类只能放在
        -[PHPhotoLibrary performChanges:completionHandler:] 或者
        -[PHPhotoLibrary performChangesAndWait:error:]方法的block中使用

        具体代码实现步骤:
        demo:

        导入框架
        #import <Photos/Photos.h>
        以下总共抽取出来了三个方法,方便点击保存按钮时调用

        // 获得刚才添加到【相机胶卷】中的图片 
        -(PHFetchResult<PHAsset *> *)createdAssets
        {
        __block NSString *createdAssetId = nil;
        // 添加图片到【相机胶卷】
        [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
         createdAssetId = [PHAssetChangeRequest creationRequestForAssetFromImage:self.imageView.image].placeholderForCreatedAsset.localIdentifier;
        } error:nil];
        if (createdAssetId == nil) return nil;
        // 在保存完毕后取出图片
        return [PHAsset fetchAssetsWithLocalIdentifiers:@[createdAssetId] options:nil];
        }
        获得【自定义相册】
        -(PHAssetCollection *)createdCollection
        {
        // 获取软件的名字作为相册的标题(如果需求不是要软件名称作为相册名字就可以自己把这里改成想要的名称)
        NSString *title = [NSBundle mainBundle].infoDictionary[(NSString *)kCFBundleNameKey];   
        // 获得所有的自定义相册
        PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
        for (PHAssetCollection *collection in collections) {
         if ([collection.localizedTitle isEqualToString:title]) {
             return collection;
         }
        }
        // 代码执行到这里,说明还没有自定义相册
        __block NSString *createdCollectionId = nil;
        // 创建一个新的相册
        [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
         createdCollectionId = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:title].placeholderForCreatedAssetCollection.localIdentifier;
        } error:nil];
        if (createdCollectionId == nil) return nil;
        // 创建完毕后再取出相册
        return [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[createdCollectionId] options:nil].firstObject;
        }
        //保存图片到相册
        -(void)saveImageIntoAlbum
        {
        // 获得相片
        PHFetchResult<PHAsset *> *createdAssets = self.createdAssets;
        // 获得相册
        PHAssetCollection *createdCollection = self.createdCollection;
        if (createdAssets == nil || createdCollection == nil) {
         [SVProgressHUD showErrorWithStatus:@"保存失败!"];
         return;
        }
        // 将相片添加到相册
        NSError *error = nil;
        [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
         PHAssetCollectionChangeRequest *request = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:createdCollection];
         [request insertAssets:createdAssets atIndexes:[NSIndexSet indexSetWithIndex:0]];
        } error:&error];
        // 保存结果
        if (error) {
         [SVProgressHUD showErrorWithStatus:@"保存失败!"];
        } else {
         [SVProgressHUD showSuccessWithStatus:@"保存成功!"];
        }
        }
        //点击保存按钮时调用
        -(IBAction)save {
        // requestAuthorization方法的功能
        1.如果用户还没有做过选择,这个方法就会弹框让用户做出选择
        1> 用户做出选择以后才会回调block
        2.如果用户之前已经做过选择,这个方法就不会再弹框,直接回调block,传递现在的授权状态给block
        PHAuthorizationStatus oldStatus = [PHPhotoLibrary authorizationStatus];
        [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
         dispatch_async(dispatch_get_main_queue(), ^{
             switch (status) {
                 case PHAuthorizationStatusAuthorized: {
                     //  保存图片到相册
                     [self saveImageIntoAlbum];
                     break;
                 } 
                 case PHAuthorizationStatusDenied: {
                     if (oldStatus == PHAuthorizationStatusNotDetermined) return;
                     NSLog(@"提醒用户打开相册的访问开关");
                     break;
                 }       
                 case PHAuthorizationStatusRestricted: {
                     [SVProgressHUD showErrorWithStatus:@"因系统原因,无法访问相册!"];
                     break;
                 }       
                 default:
                     break;
             }
         });
        }];
        用户还没有对当前App授权过(用户从未点击过Don't Allow或者OK按钮)
        PHAuthorizationStatusRestricted
        因为一些系统原因导致无法访问相册(比如家长控制)
        PHAuthorizationStatusDenied
        用户已经明显拒绝过当前App访问相片数据(用户已经点击过Don't Allow按钮)
        PHAuthorizationStatusAuthorized
        用户已经允许过当前App访问相片数据(用户已经点击过OK按钮)

二 : 获取系统的相册图片(一张或者多张)

UIImagePickerControllerSourceTypePhotoLibrary, 从所有相册中选择图片
UIImagePickerControllerSourceTypeCamera, 利用照相机拍一张图片(自定义照相机AVCaptureSession)
UIImagePickerControllerSourceTypeSavedPhotosAlbum 从Moments相册中选择图片
1.获取一张相册里的图片(图片 == 1)

获取相册中的图片

  • 1.单张
    1> UIImagePickerController
    2> AssetsLibrary框架
    3> Photos框架

    • 2.多张(>=2张)
      1> AssetsLibrary框架
      2> Photos框架
      demo1:
    • 点击屏幕时,就跳转到系统相册进行选择图片(只能选择一张照片)
      @interface ViewController () <UINavigationControllerDelegate, UIImagePickerControllerDelegate, UITableViewDelegate>
      -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
      UIImagePickerController *picker = [[UIImagePickerController alloc] init];
      picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
      picker.delegate = self;
      [self presentViewController:picker animated:YES completion:nil];
      }
      //实现代理方法<UIImagePickerControllerDelegate>
      -(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
      {
      // 关闭选择图片界面
      [picker dismissViewControllerAnimated:YES completion:nil];
      // 获得选择的图片
      UIImageView *imageView = [[UIImageView alloc] init];
      imageView.image = info[UIImagePickerControllerOriginalImage];
      imageView.frame = CGRectMake(0, 0, 100, 100);
      [self.view addSubview:imageView];
      }
      -(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
      {
      // .....
      // 关闭选择图片界面
      [picker dismissViewControllerAnimated:YES completion:nil];
      }
      2.获取多张相册里的图片(图片 >= 2)
      用到框架和实现协议一些方法
      demo2(部分重要代码):
      #import "ViewController.h"
      #import <Photos/Photos.h>
      #import <CTAssetsPickerController/CTAssetsPickerController.h>
      -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
      [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status){
        if (status != PHAuthorizationStatusAuthorized) return;     
        dispatch_async(dispatch_get_main_queue(), ^{
            CTAssetsPickerController *picker = [[CTAssetsPickerController alloc] init];
            picker.delegate = self;
            // 显示选择的索引
            picker.showsSelectionIndex = YES;
            // 设置相册的类型:相机胶卷 + 自定义相册
            picker.assetCollectionSubtypes = @[
              @(PHAssetCollectionSubtypeSmartAlbumUserLibrary),
              @(PHAssetCollectionSubtypeAlbumRegular)];
            // 不需要显示空的相册
            picker.showsEmptyAlbums = NO;
            [self presentViewController:picker animated:YES completion:nil];
        });
      }];
      }
      #pragma mark - <CTAssetsPickerControllerDelegate>
      -(BOOL)assetsPickerController:(CTAssetsPickerController *)picker shouldSelectAsset:(PHAsset *)asset
      {
      NSInteger max = 2;  
      if (picker.selectedAssets.count >= max) {
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:[NSString stringWithFormat:@"最多选择%zd张图片", max] preferredStyle:UIAlertControllerStyleAlert];
        [alert addAction:[UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:nil]];
        [picker presentViewController:alert animated:YES completion:nil];
        // 这里不能使用self来modal别的控制器,因为此时self.view不在window上
        return NO;
      }
      return YES;
      }
      -(void)assetsPickerController:(CTAssetsPickerController *)picker didFinishPickingAssets:(NSArray *)assets
      {
      // 关闭图片选择界面
      [picker dismissViewControllerAnimated:YES completion:nil];
      // 基本配置
      CGFloat scale = [UIScreen mainScreen].scale;
      PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
      options.resizeMode   = PHImageRequestOptionsResizeModeExact;
      options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
      // 遍历选择的所有图片
      for (NSInteger i = 0; i < assets.count; i++) {
        PHAsset *asset = assets[i];
        CGSize size = CGSizeMake(asset.pixelWidth / scale, asset.pixelHeight / scale);
        // 获取图片
        [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeDefault options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
            UIImageView *imageView = [[UIImageView alloc] init];
            imageView.image = result;
            imageView.frame = CGRectMake((i % 3) * 110, (i / 3) * 110, 100, 100);
            [self.view addSubview:imageView];
        }];
      }
      }
      效果:
<think> 我们正在讨论的是微信小程序的API调用,具体是关于选择图片的功能。根据用户需求,我们需要调用微信小程序的API,实现拍照者从相册选择一张图片的功能。 微信小程序提供了wx.chooseImage方法,但是注意,这个方法在基础库2.21.0及以上版本已经不再维护,而是推荐使用wx.chooseMedia。不过,为了兼容性当前文档,我们通常还是使用wx.chooseImage,但也要注意新版本的变化。 但是,根据微信官方文档更新,wx.chooseImage自2021年4月起已停止维护,推荐使用wx.chooseMedia。因此,我们应该使用wx.chooseMedia来实现这个功能,并且限制只能选择一张图片。 使用wx.chooseMedia的步骤: 1. 在页面的js文件中,编写一个函数(例如chooseImage)来调用wx.chooseMedia。 2. 配置参数:count设置为1(表示只能选1个),mediaType设置为['image'](表示只选择图片),sourceType可以选择['album', 'camera'](表示可以从相册相机选择)。 3. 成功回调中获临时文件路径。 注意:在微信小程序中使用该API需要用户授权,但微信小程序已经调整了授权策略,部分接口可以直接调用,用户操作时触发授权弹窗。对于摄像头相册的访问,需要在app.json中配置权限声明。 但是,根据最新的微信文档,使用wx.chooseMedia不需要在app.json中额外声明,但是需要用户授权。如果用户拒绝,则需要引导用户重新授权。 另外,从微信基础库2.21.0开始,wx.chooseMedia是推荐使用的API。 下面是一个示例代码: 在页面的js文件中: ```javascript Page({ chooseImage() { wx.chooseMedia({ count: 1, // 只能选择一张图片 mediaType: ['image'], sourceType: ['album', 'camera'], // 可以从相册相机选择 success: (res) => { // res.tempFiles是一个数组,因为count为1,所以第一个 const tempFile = res.tempFiles[0]; const tempFilePath = tempFile.tempFilePath; // 这里就可以得到图片的临时路径,可以用于显示上传 console.log(tempFilePath); // 将图片临时路径设置到页面数据中,以便在wxml中显示 this.setData({ imageSrc: tempFilePath }); }, fail: (err) => { console.error(err); } }); } }) ``` 在wxml文件中,我们可以放置一个按钮来触发选择图片事件,并显示选择的图片: ```html <button bindtap="chooseImage">选择图片</button> <image src="{{imageSrc}}" mode="widthFix"></image> ``` 注意:如果用户拒绝授权,可以在fail回调中处理,者使用wx.openSetting打开设置页面引导用户重新授权。但是注意,wx.openSetting需要用户主动触发,不能直接调用。 另外,关于用户授权,我们可以在app.js中使用wx.getSetting检查用户是否已经授权过,如果没有授权,则可以在需要的时候调用API,此时会弹出授权窗口。但微信调整后,部分API调用时如果用户未授权会直接弹出授权窗口,所以我们可以直接调用wx.chooseMedia,如果用户从未授权,则会弹出授权窗口。 但是,如果用户之前拒绝过,则再次调用不会弹出授权窗口,而是进入fail回调。在fail回调中,我们可以提示用户去设置页面打开授权。 处理拒绝授权的示例代码: ```javascript fail: (err) => { if (err.errno === 12100) { // 用户拒绝授权 wx.showModal({ title: '提示', content: '您拒绝了授权,是否去设置页面打开授权?', success: (res) => { if (res.confirm) { wx.openSetting({ success: (res) => { // 用户打开了设置页面,无论用户是否打开授权,返回后我们都不再处理,由用户再次点击按钮触发 } }); } } }); } } ``` 注意:错误码12100表示用户拒绝授权。但是具体错误码需要参考官方文档,因为可能会变化。 另一种做法是,在调用wx.chooseMedia之前,先检查用户是否已经授权,如果没有授权则提前请求授权。可以使用wx.authorize,但是注意wx.authorize只会在用户第一次触发时弹窗,如果用户拒绝,则后续不会再弹窗,需要引导用户去设置页面打开。 所以,我们可以这样优化: 1. 在调用wx.chooseMedia前,使用wx.getSetting获用户的授权设置。 2. 如果用户已经授权,则直接调用wx.chooseMedia。 3. 如果用户未授权,则调用wx.authorize请求授权,授权成功后再调用wx.chooseMedia,如果授权失败,则提示用户去设置页面。 但是,微信官方文档中提到,对于scope.camerascope.album(实际上在wx.chooseMedia中使用的是scope.media)的授权,可以直接调用API,由微信在调用时处理授权。因此,为了简化,我们可以直接调用wx.chooseMedia,然后在失败时处理未授权的情况。 综上所述,我们给出使用wx.chooseMedia的完整代码示例,包括处理授权失败的情况。 注意:wx.chooseMedia使用的授权是scope.media,它包括了相册相机,所以不需要分别申请。 因此,我们按照以下步骤实现: 1. 在页面中放置一个按钮,绑定chooseImage事件。 2. 在js文件中实现chooseImage函数,调用wx.chooseMedia,并设置参数。 3. 成功回调中获临时文件路径并显示。 4. 失败回调中处理错误,特别是用户拒绝授权的情况。 这里我们采用直接调用wx.chooseMedia的方式,并在失败回调中处理授权问题。 另外,注意wx.chooseMedia返回的临时路径在本次启动小程序期间可以使用,如果需要持久保存,则需要上传到服务器。 最后,我们还需要注意,在真机上测试时,需要打开调试模式者已经获得授权,否则可能会遇到权限问题。 以上就是原生微信小程序调用拍照选择功能并只选择一张图片的实现方法。 由于用户要求只选择一张图片,所以count设置为1。 下面我们给出完整的示例代码。 页面JS文件(例如index.js): ```javascript Page({ data: { imageSrc: '' // 用于存储图片路径 }, chooseImage() { wx.chooseMedia({ count: 1, mediaType: ['image'], sourceType: ['album', 'camera'], success: (res) => { console.log(res.tempFiles) const tempFile = res.tempFiles[0]; if (tempFile) { this.setData({ imageSrc: tempFile.tempFilePath }); } }, fail: (err) => { console.error(err); // 处理用户拒绝授权的情况 if (err.errMsg && err.errMsg.indexOf('auth deny') !== -1) { // 者通过错误码判断,但具体错误码需要看文档,这里使用错误信息判断 wx.showModal({ title: '提示', content: '您拒绝了授权,是否去设置页面打开授权?', success: (res) => { if (res.confirm) { wx.openSetting(); } } }); } } }); } }); ``` 页面WXML文件(例如index.wxml): ```html <button bindtap="chooseImage">选择图片</button> <image src="{{imageSrc}}" mode="widthFix" wx:if="{{imageSrc}}"></image> ``` 这样,用户点击按钮后,可以选择拍照者从相册选择一张图片,然后显示在页面上。 注意:如果用户拒绝授权,会弹窗提示去设置页面打开授权。用户点击确定后,会跳转到设置页面,用户可以在设置页面打开授权。 另外,我们使用了wx:if来判断是否有图片路径,如果没有则不显示image组件。 以上就是在原生微信小程序中调用拍照选择功能且只选择一张图片的方法。 </think>在原生微信小程序中调用拍照选择图片功能并限制只选择一张图片,可以通过以下步骤实现: ### 实现方法 1. **使用 `wx.chooseMedia` API**(推荐) 这是微信官方推荐的媒体文件选择接口: ```javascript wx.chooseMedia({ count: 1, // 限制选择1张 mediaType: ['image'], // 只允许图片类型 sourceType: ['album', 'camera'], // 相册相机 success: (res) => { console.log('文件路径:', res.tempFiles[0].tempFilePath) // 这里获临时路径用于显示上传 } }) ``` 2. **兼容旧版的 `wx.chooseImage`**(基础库<2.21.0) ```javascript wx.chooseImage({ count: 1, // 关键参数 sourceType: ['album', 'camera'], success: (res) => { const tempFilePaths = res.tempFilePaths console.log('文件路径:', tempFilePaths[0]) } }) ``` ### 关键配置说明 | 参数 | 值 | 作用 | |-------------|---------------------|--------------------------| | `count` | 1 | 限制选择数量为单张 | | `mediaType` | `['image']` | 限定图片类型 | | `sourceType`| `['album','camera']`| 允许相册相机两种来源 | ### 注意事项 1. **权限声明**:在`app.json`中添加所需权限: ```json { "permission": { "scope.camera": { "desc": "用于拍照功能" }, "scope.album": { "desc": "用于访问相册" } } } ``` 2. **用户拒绝处理**: ```javascript fail: (err) => { if (err.errMsg.includes('auth deny')) { wx.showToast({ title: '需要授权才能使用', icon: 'none' }) } } ``` 3. **临时路径有效期**: 获的`tempFilePath`在小程序本次启动期间可用,如需长期使用需上传至服务器。 ### 完整示例代码 ```javascript Page({ data: { imagePath: '' }, chooseSingleImage() { wx.chooseMedia({ count: 1, mediaType: ['image'], success: res => { this.setData({ imagePath: res.tempFiles[0].tempFilePath }) }, fail: err => { console.error('选择失败:', err) } }) } }) ``` ```html <!-- WXML --> <button bindtap="chooseSingleImage">选择图片</button> <image src="{{imagePath}}" mode="widthFix" wx:if="{{imagePath}}"/> ``` ### 最佳实践建议 1. 优先使用`wx.chooseMedia`(基础库>=2.21.0) 2. 在`onLoad`生命周期预请求授权: ```javascript wx.authorize({ scope: 'scope.camera' }) wx.authorize({ scope: 'scope.album' }) ``` 3. 大处理建议压缩: ```javascript sizeType: ['compressed'] // 在chooseImage中启用压缩 ``` [^1]: 微信官方文档 - 媒体选择API
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值