基于PhotoViewPicker对图片进行操作

场景描述

用户有时需要分享或保存图片、视频等用户文件,开发者可以通过系统预置的文件选择器(FilePicker),实现该能力。通过Picker访问相关文件,将拉起对应的应用,引导用户完成界面操作,接口本身无需申请权限。PhotoViewPicker:适用于图片或视频类型文件的选择与保存。优选使用PhotoAccessHelper的PhotoViewPicker来选择文件。当前PhotoViewPicker对接的选择资源来自于图库,保存位置为系统文件管理器的特定目录,因此使用save接口保存的图片或视频无法在图库中展示。如需在图库中展示,请使用安全控件创建媒体资源

场景一:从图库获取图片,并通过image组件显示

场景二:对图库获取的图片进行操作

场景三:保存图片

方案描述

场景一:从图库获取图片,并通过image组件显示

效果图

方案

  • 创建图库选择器实例,调用select()接口拉起图库界面进行文件选择。文件选择成功后,返回PhotoSelectResult结果集。
  • select返回的uri权限是只读权限,可以根据结果集中uri进行读取文件数据操作。
  • 根据返回uri创建pixelMap
  • 将pixelMap通过image组件送显

核心代码

Image(this.pixelMap).width(200).height(200) 
  Button('打开相册') 
          .onClick(() => { 
            //创建图库选择器对象实例 
            const photoViewPicker = new picker.PhotoViewPicker(); 
            //调用select()接口拉起图库界面进行文件选择,文件选择成功后,返回PhotoSelectResult结果集 
            photoViewPicker.select().then(async (photoSelectResult: picker.PhotoSelectResult) => { 
              //用一个全局变量存储返回的uri 
              selectUris = photoSelectResult.photoUris; 
              console.info('photoViewPicker.select to file succeed and uris are:' + selectUris); 
              //使用fs.openSync接口,通过uri打开这个文件得到fd 
              let file = fs.openSync(selectUris[0], fs.OpenMode.READ_ONLY); 
              console.info('file fd: ' + file.fd); 
              //根据文件fd创建imagSource 
              const imageSource: image.ImageSource = image.createImageSource(file.fd); 
              //完成后关闭fd 
              fs.closeSync(file); 
              let decodingOptions: image.DecodingOptions = { 
                editable: true, 
                desiredPixelFormat: 3, 
              } 
              //创建pixelMap 
              imageSource.createPixelMap(decodingOptions).then(async (pixelMap1: image.PixelMap) => { 
                this.pixelMap = pixelMap1; 
              }); 
            }).catch((err: BusinessError) => { 
              console.error(`Invoke photoViewPicker.select failed, code is ${err.code}, message is ${err.message}`); 
            }) 
          })

场景二:对图库获取的图片进行操作

效果图

方案

  • 调用pixelMap的 rotate方法实现对图面的旋转
  • 通过imagePacker的api实现图片编码压缩

核心代码

  Button("图片操作") 
          .margin({ top: 20 }) 
          .onClick(async (event: ClickEvent) => { 
            if (this.pixelMap) { 
              //旋转90度 
              await this.pixelMap.rotate(90); 
              //创建图像编码ImagePacker对象。 
              const imagePackerApi = image.createImagePacker(); 
              //设置编码输出流和编码参数。 
              // format为图像的编码格式;quality为图像质量,范围从0-100,100为最佳质量。 
              let packOpts: image.PackingOption = { format: "image/jpeg", quality: 100 }; 
              //通过PixelMap进行编码 
              imagePackerApi.packing(this.pixelMap, packOpts).then(async (data: ArrayBuffer) => { 
                // data 为打包获取到的文件流,写入文件保存即可得到一张图片 
                arrayBuffer = data; 
              }).catch((error: BusinessError) => { 
                console.error('Failed to pack the image. And the error is: ' + error); 
              }) 
 
            } 
          })

场景三:保存图片

方案一:通过photoViewPicker将图片保存到系统文件管理器管理特定目录

当前所有picker的save接口都是用户可感知的,具体行为是拉起FilePicker, 将文件保存在系统文件管理器管理的特定目录,与图库管理的资源隔离,无法在图库中看到。

效果图

调用save()接口拉起FilePicker界面进行文件保存。用户选择目标文件夹,用户选择与文件类型相对应的文件夹,即可完成文件保存操作。保存成功后,并用一个全局变量存储返回的uri。

使用fs.openSync接口,通过选择和保存uri打开这两个文件得到fd,这里需要注意接口权限参数分别是fs.OpenMode.READ_ONLY和fs.OpenMode.WRITE_ONLY。再调用fs.copyFileSync接口进行复制,修改完成后关闭两个文件。

核心代码

try { 
              const photoSaveOptions = new picker.PhotoSaveOptions(); // 创建文件管理器保存选项实例 
              photoSaveOptions.newFileNames = ["PhotoViewPicker01.png"]; // 保存文件名(可选),方括号里的文件名自定义,每次不能重复,设备里已有这个文件的话,名字就需要改个不一样的,不然接口会报错 
              const photoViewPicker = new picker.PhotoViewPicker(); 
              try { 
                //调用save()接口拉起FilePicker界面进行文件保存。用户选择目标文件夹,用户选择与文件类型相对应的文件夹,即可完成文件保存操作 
                let photoSaveResult = await photoViewPicker.save(photoSaveOptions); 
                if (photoSaveResult != undefined) { 
                  //保存成功后,并用一个全局变量存储返回的uri 
                  saveUris = photoSaveResult; 
                  console.info('photoViewPicker.save to file succeed and uris are:' + photoSaveResult); 
                } 
              } catch (error) { 
                let err: BusinessError = error as BusinessError; 
                console.error(`[picker] Invoke photoViewPicker.save failed, code is ${err.code}, message is ${err.message}`); 
              } 
            } catch (error) { 
              let err: BusinessError = error as BusinessError; 
              console.info("[picker] photoViewPickerSave error = " + JSON.stringify(err)); 
            }
 try { 
              //使用fs.openSync接口,通过选择和保存uri打开这两个文件得到fd,这里需要注意接口权限参数分别是fs.OpenMode.READ_ONLY和fs.OpenMode.WRITE_ONLY 
              let photoSelect = fs.openSync(selectUris[0], fs.OpenMode.READ_ONLY); 
              let photoSave = fs.openSync(saveUris[0], fs.OpenMode.WRITE_ONLY); 
              //再调用fs.copyFileSync接口进行复制 
              fs.copyFileSync(photoSelect.fd, photoSave.fd); 
              //完成后关闭两个文件。 
              fs.close(photoSelect); 
              fs.close(photoSave); 
            } catch (error) { 
              let err: BusinessError = error as BusinessError; 
              console.info("[picker] Photo Save error = " + JSON.stringify(err)); 
            } 
 
          })

方案二:通过安全控件按钮保存图片到图库

保存控件是一种特殊的安全控件,它允许用户通过点击按钮临时获取存储权限,而无需通过权限弹框进行授权确认

集成保存控件后,当用户点击该控件时,应用会获得10秒内单次访问媒体库特权接口的授权。这适用于任何需要将文件保存到媒体库的应用场景,例如保存图片或视频等。

与需要触发系统应用并由用户选择具体保存路径的Picker不同,保存控件可以直接保存到媒体库路径,使得操作更为便捷。

使用场景:应用仅需要在前台期间,短暂使用保存图片的特性,不需要长时间使用。此时,可以直接使用安全控件中的保存控件,免去权限申请和权限请求等环节(创建媒体资源需要在应用中申请相册管理模块权限'ohos.permission.WRITE_IMAGEVIDEO'),获得临时授权,保存对应图片。

约束与限制

  • 应用在onClick()触发回调到调用媒体库特权接口的时间间隔不能大于10秒。
  • 用户点击一次控件,仅获取一次授权调用。
  • 为了保障用户的隐私不被恶意应用获取,应用需确保安全控件是可见的且用户能够识别的。开发者需要合理的配置控件的尺寸、颜色等属性,避免视觉混淆的情况,如果发生因控件的样式不合法导致授权失败的情况,请检查设备错误日志。

效果图

1)设置安全控件按钮属性。
2)创建安全控件按钮。
3)调用PhotoAccessHelper.createAsset接口创建图片资源。
4)根据资源uri创建file并写入图片数据。

核心代码

 @State saveButtonOptions: SaveButtonOptions = { 
    icon: SaveIconStyle.FULL_FILLED, //设置保存按钮的图标风格,不传入该参数表示没有图标,icon和text至少存在一个;这里设置为:保存按钮展示填充样式图标。 
    text: SaveDescription.SAVE_IMAGE, //设置保存按钮的文本描述, 不传入该参数表示没有文字描述,这里设置为:保存按钮的文字描述为“保存图片”。 
    buttonType: ButtonType.Capsule   //设置保存按钮的背景样式,   不传入该参数表示没有背景。这里设置为:胶囊型按钮(圆角默认为高度的一半)。 
  } // 设置安全控件按钮属性
SaveButton(this.saveButtonOptions)// 创建安全控件按钮 
  .padding(10) 
    //点击动作触发该回调。 
  .onClick(async (event, result: SaveButtonOnClickResult) => { 
    //SaveButtonOnClickResult枚举说明 
    //名称 枚举值  描述 
    // SUCCESS 0  保存按钮点击成功。 
    // TEMPORARY_AUTHORIZATION_FAILED  1  保存按钮点击后权限授权失败。 
 
    if (result == SaveButtonOnClickResult.SUCCESS) { 
      // result:存储权限的授权结果,授权时长为10秒,即触发点击后,可以在10秒之内不限制次数的调用特定媒体库接口,超出10秒的调用会鉴权失败。 
      try { 
        let context = getContext(); 
        //获取相册管理模块的实例,用于访问和修改相册中的媒体文件 
        let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context); 
        // onClick触发后10秒内通过createAsset接口创建图片文件,10秒后createAsset权限收回 
        let uri = await phAccessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg'); // 创建媒体文件 
        console.info('createAsset successfully, uri: ' + uri); 
        let file = await fs.open(uri, fs.OpenMode.READ_WRITE || fs.OpenMode.CREATE); 
        //   // 使用uri打开文件,可以持续写入内容,写入过程不受时间限制 
        await fs.write(file.fd, arrayBuffer); 
        /// 关闭文件 
        await fs.close(file); 
        promptAction.showToast({ message: '已保存至相册!' }); 
      } catch (err) { 
        console.error('createAsset failed, message = ', err); 
      } 
    } else { 
      console.error('SaveButtonOnClickResult createAsset failed'); 
    } 
  })

方案三:动态申请acl权限,保存图片到图库

PhotoAccessHelper.createAsset接口 需要ohos.permission.WRITE_IMAGEVIDEO权限,ohos.permission.WRITE_IMAGEVIDEO权限为系统等级,该权限当前可申请的场景与功能:应用需要克隆、备份或同步图片/视频类文件。   

权限等级应用APL等级是一一对应的。原则上,拥有低APL等级的应用默认无法申请更高等级的权限。访问控制列表ACL(Access Control List)提供了解决低等级应用访问高等级权限问题的特殊渠道。

允许ACL跨级别申请

当前仅支持部分权限通过应用市场(AGC)使用ACL的方式跨级别申请权限。在申请发布Profile时,同步提交申请ACL权限

系统权限均定义了“ACL使能”字段,如果应用需要使用跨级别权限时,需使用ACL方式来申请对应权限。在应用权限列表中标记“ACL使能:TRUE”的为支持ACL的权限。当该权限的ACL使能为TRUE,应用可以使用ACL方式跨级别申请该权限。

支持ACL权限

从DevEco Studio 4.0 Release版本起,针对HarmonyOS工程,DevEco Studio支持在调测阶段通过自动签名快速申请ACL权限。

效果图

  • 在module.json5文件中配置权限
  • requestPermissionsFromUser方法弹框向用户动态申请权限
  • 权限申请成功后通过createAsset接口创建图片文件

核心代码

"requestPermissions": [ 
{ 
  "name": "ohos.permission.WRITE_IMAGEVIDEO", 
"reason": "$string:app_name", 
"usedScene": { 
  "abilities": [ 
  "FormAbility" 
  ], 
  "when":"always" 
} 
} 
]
async requestPermissionsFn() { 
  Logger.info(TAG, `requestPermissionsFn entry`); 
  try { 
    //申请相册管理模块权限'ohos.permission.WRITE_IMAGEVIDEO' 
    this.atManager.requestPermissionsFromUser(this.appContext, [ 
      'ohos.permission.WRITE_IMAGEVIDEO' 
 
    ]).then(() => { 
      Logger.info(TAG, `request Permissions success!`); 
      //权限申请成功,保存到图库 
      this.SavePicture() 
 
    }) 
  } catch (err) { 
    Logger.info(TAG, `requestPermissionsFromUser call Failed! error: ${err.code}`); 
 
  } 
}
async SavePicture(): Promise<void> { 
  // 
  try { 
  let context = getContext(); 
  //获取相册管理模块的实例,用于访问和修改相册中的媒体文件 
  let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context); 
  //通过createAsset接口创建图片文件 
  let uri = await phAccessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg'); // 创建媒体文件 
  console.info('createAsset successfully, uri: ' + uri); 
  let file = await fs.open(uri, fs.OpenMode.READ_WRITE || fs.OpenMode.CREATE); 
  // 使用uri打开文件,可以持续写入内容,写入过程不受时间限制 
  await fs.write(file.fd, arrayBuffer); 
  // 关闭文件 
  await fs.close(file); 
} catch (err) { 
  console.error('createAsset failed, message = ', err); 
}
<think>好的,用户想查找关于PhotoViewPicker的使用指南和示例代码,特别是在IT技术方面的信息。首先,我需要回忆一下PhotoViewPicker的常见应用场景和相关的技术文档。根据提供的引用内容,引用[1]提到PhotoViewPicker.select()可以拉起图库界面,用户可以选择多个文件,引用[2]和[3]也涉及图片处理和保存路径的相关内容。 首先,用户可能需要了解如何在代码中调用PhotoViewPicker,比如在Android或HarmonyOS中的实现方式。根据引用[1],示例代码可能涉及到调用select()方法,并处理返回的结果。需要确认是否有特定的参数需要设置,比如选择模式(单选或多选)、文件类型过滤等。 接下来,示例代码的结构也很重要。用户可能需要一个完整的函数或方法示例,展示如何初始化PhotoViewPicker,设置参数,处理返回的URI或文件路径。同时,需要解释关键代码的作用,比如startActivityForResult处理选择结果,或使用Intent配置选择器。 另外,引用[3]提到保存控件可以直接保存到媒体库路径,这可能与PhotoViewPicker的保存功能相关,但用户的问题更侧重于选择图片而非保存。不过,可能需要简要提及相关功能作为扩展。 还要注意用户可能的开发环境,比如HarmonyOS NEXT中使用ArkTS,如引用[4]所述。如果PhotoViewPicker在该环境下的用法不同,可能需要调整示例代码。但根据现有引用,示例代码可能基于Android或HarmonyOS的Java/Kotlin或ArkTS。 需要确保回答结构清晰,分步骤说明,并提供示例代码。同时,根据用户提供的引用,引用相关的部分,如拉起图库、选择文件等,末尾添加引用标识。 最后,生成相关问题时要围绕PhotoViewPicker的功能、参数配置、结果处理、与其他组件的对比(如引用[3]中的Picker对比)以及在不同平台上的应用。</think># PhotoViewPicker 使用指南与示例代码 ## 一、功能概述 PhotoViewPicker 是一种用于在移动应用中实现图片选择功能的组件,可调用系统图库界面进行多文件选择,支持本地/网络图片的展示与操作[^1][^2]。与需要用户手动指定保存路径的控件不同,它直接集成系统图库功能,简化了操作流程[^3]。 --- ## 二、基础使用方法 ### 1. 调用图库界面 通过 `select()` 方法拉起系统图库,核心代码结构如下: ```typescript import photoViewPicker from '@ohos.file.photoViewPicker'; // 创建PhotoSelectOptions配置对象 let photoSelectOptions = new photoViewPicker.PhotoSelectOptions(); photoSelectOptions.MIMEType = photoViewPicker.PhotoViewMIMETypes.IMAGE_TYPE; // 限定选择类型为图片 photoSelectOptions.maxSelectNumber = 5; // 设置最大选择数量 // 调用选择器 try { let photoSelectResult = await photoViewPicker.select(photoSelectOptions); console.log('PhotoViewPicker selection succeeded, result:' + JSON.stringify(photoSelectResult)); } catch (err) { console.error('PhotoViewPicker selection failed, err:' + JSON.stringify(err)); } ``` *关键参数说明*: - `MIMEType`:指定可选择的文件类型(如图片/视频) - `maxSelectNumber`:控制多选数量上限 ### 2. 处理选择结果 获取的 `photoSelectResult` 对象包含用户选择的文件URI列表: ```typescript if (photoSelectResult.photoUris.length > 0) { let firstImageUri = photoSelectResult.photoUris[0]; // 使用ImageKnife加载图片 imageKnife.load(firstImageUri).then(() => { console.log('Image loaded successfully'); }); } ``` 建议配合 [ImageKnife](https://gitee.com/openharmony-tpc/imageknife) 等三方库实现图片加载与渲染[^2] --- ## 三、高级配置 ### 1. 混合文件类型选择 ```typescript photoSelectOptions.MIMEType = photoViewPicker.PhotoViewMIMETypes.IMAGE_VIDEO_TYPE; // 允许选择图片和视频 photoSelectOptions.minSelectNumber = 2; // 设置最少选择数量 ``` ### 2. 选择界面定制 通过 `PhotoViewPickerConfig` 可修改选择器UI样式: ```typescript let config: photoViewPicker.PhotoViewPickerConfig = { title: '自定义标题', themeColor: '#FF0000', gridCount: 4 // 设置图片网格列数 }; photoViewPicker.setConfig(config); ``` --- ## 四、与其他组件联动 ### 1. 结合相机拍照 ```typescript // 调用系统相机 let camera = await media.createCamera(getContext(this)); let photo = await camera.takePhoto(); // 将拍摄结果加入选择器列表 photoSelectResult.photoUris.push(photo.uri); ``` ### 2. 保存到媒体库 使用 `MediaLibrary` API 直接保存处理后的图片: ```typescript import mediaLibrary from '@ohos.multimedia.mediaLibrary'; const mediaLib = mediaLibrary.getMediaLibrary(getContext(this)); mediaLib.createAsset(mediaLibrary.MediaType.IMAGE, "processed_image.jpg", (err, asset) => { if (!err) { console.log('Saved to media library: ' + asset.uri); } }); ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值