鸿蒙开发实践——基于PhotoViewPicker对图片进行操作

场景一:从图库获取图片,并通过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);
      })
 
    }
  })

DD一下:在鸿蒙开发过程中,小编已经踩过无数坑,为了让大家少走弯路,小编结合自身实践经验整理了一套全面的学习攻略。大家可以进行参考学习:鸿蒙全栈开发学习指南

1.鸿蒙全栈开发学习路线
2.OpenHarmony开发基础
3.OpenHarmony北向开发环境搭建
4.鸿蒙南向开发环境的搭建
5.鸿蒙生态应用开发白皮书V2.0 & V3.0
6.鸿蒙开发面试真题(含参考答案) 
7.TypeScript入门学习手册
8.OpenHarmony 经典面试题(含参考答案)
9.OpenHarmony设备开发入门【最新版】
10.沉浸式剖析OpenHarmony源代码
11.系统定制指南
12.【OpenHarmony】Uboot 驱动加载流程
13.OpenHarmony构建系统--GN与子系统、部件、模块详解
14.ohos开机init启动流程
15.鸿蒙版性能优化指南
......

场景三:保存图片:

方案一:通过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并写入图片数据。

核心代码

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));
}

方案三:动态申请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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值