• 鸿蒙NEXT如何保存图片到图库中
  • 发布于 1周前
  • 71 热度
    0 评论
官网中介绍了两种方法,不需要申请相册管理模块权限的方式,就可以实现图片保存到图库中。即安全控件和授权弹框的方式。看了官网中的代码,使用这两种方式,前提是都需要获取到图片的沙盒路径,安全控件还多了一种方式,通过ArrayBuffer。这些我在下面的代码中都会分享。那如何获取到沙盒路径呢?我们有的只是远程的图片链接。那么就需要用到request模块中的downloadFile方法了。用户下载远程图片,到沙盒路径中。

看代码:
下载图片:
/**
 * 堆代码 duidaima.com
 * 下载图片 ,获取沙盒路径(也可以获取到ArrayBuffer数据)
 * @param uiContext UI上下文对象
 * @param src 图片路径
 * @returns 沙盒路径+图片后缀(也可以获取到ArrayBuffer数据)
 */
function handleDownloadFileGetBuffer(uiContext: UIContext, src: string): Promise<ISaveImage> {
  return new Promise((resolve: (value: ISaveImage) => void, reject: () => void) => {
    const context: common.UIAbilityContext = uiContext.getHostContext() as common.UIAbilityContext;
    /* 获取图片的后缀名 */
    const _extension = src.split('.').pop();
    const extension: string = _extension ? _extension : 'jpg'; /*如果没有后缀,默认一个*/
    /* 创建文件路径,相同图片也需要不同的路径,不然报错,这也是不用后端返回的文件名称的原因 */
    const filePath = context.filesDir + '/' + util.generateRandomUUID(true) + '.' + extension;
    console.log('filePath', filePath)
    try {
      request.downloadFile(context, {
        url: IMG_URL + src,
        filePath
      }).then((downloadTask: request.DownloadTask) => {
        downloadTask.on('complete', () => {
          const file = fs.openSync(filePath, fs.OpenMode.READ_WRITE);
          // 获取文件信息,得到图片的大小,去创建对应大小的ArrayBuffer的缓冲区
          const fileInfo = fs.statSync(filePath);
          const arrayBuffer = new ArrayBuffer(fileInfo.size);
          fs.readSync(file.fd, arrayBuffer);
          fs.closeSync(file);
          const res: ISaveImage = {
            extension,
            sandboxUri: filePath,
            arrayBuffer
          }
          resolve(res)
        })
      }).catch((err: BusinessError) => {
        console.error(`Invoke downloadTask failed, code is ${err.code}, message is ${err.message}`);
      });
    } catch (error) {
      let err: BusinessError = error as BusinessError;
      console.error(`Invoke downloadFile failed, code is ${err.code}, message is ${err.message}`);
    }
  })
}

/* 保存图片的接口 */
interface ISaveImage {
  extension: string; /*后缀名*/
  sandboxUri: string;
  arrayBuffer: ArrayBuffer /*资源buffer对象*/
}
其中arrayBuffer的数据获取,可以删除了。因为介绍知识点的缘故保留。通过沙盒路径的方式更加方便。

方法1:安全控件
/**
 *  通过安全控件的保存控件 来保存图片
 * @param uiContext ui上下文对象
 * @param src  图片的路径信息
 * @param result 保存控件的点击回调事件
 */
export async function handleSaveImage(uiContext: UIContext, src: string, result: SaveButtonOnClickResult) {
  if (src == "") {
    showToast(uiContext, "没有可保存的图片");
    return;
  }
  const res = await handleDownloadFileGetBuffer(uiContext, src);
  if (result == SaveButtonOnClickResult.SUCCESS) {
    try {
      const context: Context = uiContext.getHostContext() as common.UIAbilityContext;
      const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
      const photoType: photoAccessHelper.PhotoType = photoAccessHelper.PhotoType.IMAGE;
      const assetChangeRequest: photoAccessHelper.MediaAssetChangeRequest =
        photoAccessHelper.MediaAssetChangeRequest.createAssetRequest(context, photoType, res.extension);
      // assetChangeRequest.addResource(photoAccessHelper.ResourceType.IMAGE_RESOURCE, res.arrayBuffer);
      assetChangeRequest.addResource(photoAccessHelper.ResourceType.IMAGE_RESOURCE, res.sandboxUri);
      await phAccessHelper.applyChanges(assetChangeRequest);
      showToast(uiContext, "图片保存成功");
    } catch (err) {
      console.error(`create asset failed with error: ${err.code}, ${err.message}`);
    }
  } else {
    console.error('SaveButtonOnClickResult create asset failed');
  }
}
使用安全控件的方式,需要使用SaveButton组件
 // 创建安全控件按钮,去保存图片。
SaveButton({ text: SaveDescription.SAVE_TO_GALLERY, buttonType: ButtonType.Capsule })
          .backgroundColor("#fff")
          .fontColor("#167FFF")
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .onClick((_event, result: SaveButtonOnClickResult) => {
            handleSaveImage(this.getUIContext(), this.rentStaffQrCode.url, result);
})
方法2:授权弹框
/**
 * 通过授权弹框的方式保存图片
 * @param uiContext ui上下文对象
 * @param src  图片的路径信息
 */
export async function handleShowAssetsCreationDialogSaveImage(uiContext: UIContext, src: string) {
  if (src == "") {
    showToast(uiContext, "没有可保存的图片");
    return;
  }
  const res = await handleDownloadFileGetBuffer(uiContext, src);
  try {
    // 指定待保存到媒体库的位于应用沙箱的图片uri。
    let srcFileUri = res.sandboxUri;
    let srcFileUris: Array<string> = [
      srcFileUri
    ];
    // 指定待保存照片的创建选项,包括文件后缀和照片类型,标题和照片子类型可选。
    let photoCreationConfigs: Array<photoAccessHelper.PhotoCreationConfig> = [
      {
        fileNameExtension: res.extension,
        photoType: photoAccessHelper.PhotoType.IMAGE
      }
    ];
    // 基于弹窗授权的方式获取媒体库的目标uri。
    const context: Context = uiContext.getHostContext() as common.UIAbilityContext;
    const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
    let desFileUris: Array<string> = await phAccessHelper.showAssetsCreationDialog(srcFileUris, photoCreationConfigs);
    // 将来源于应用沙箱的照片内容写入媒体库的目标uri。
    let desFile: fileIo.File = await fileIo.open(desFileUris[0], fileIo.OpenMode.WRITE_ONLY);
    let srcFile: fileIo.File = await fileIo.open(srcFileUri, fileIo.OpenMode.READ_ONLY);
    await fileIo.copyFile(srcFile.fd, desFile.fd);
    fileIo.closeSync(srcFile);
    fileIo.closeSync(desFile);
    console.info('create asset by dialog successfully');
    showToast(uiContext, "图片保存成功");
  } catch (err) {
    console.error(`failed to create asset by dialog successfully errCode is: ${err.code}, ${err.message}`);
  }
}
授权弹框的方式,不需要用到SaveButton组件,
 Text('保存至图库')
    .backgroundColor("#fff")
    .fontColor("#167FFF")
    .fontSize(20)
    .fontWeight(FontWeight.Bold)
    .margin({ transform: translateY( 20, bottom: 20 })
    .onClick(()=>{   handleShowAssetsCreationDialogSaveImage(this.getUIContext(), this.rentStaffQrCode.url);
})
就是有一点,看着弹出很大一个框,感觉可以预览,但实际上无法预览,这个在官网中也明确说明了,无法预览,我们就不去纠结为什么这么显示了。最近看到鸿蒙官方有活动,到2025年年底的时候,如果成功上架一个APP最高有1w元的奖励,我感觉可以试试,公司项目也不是很难,最后4个多月加油。
用户评论