一、需求场景

app内分享固定图片,可以将图片保存到相册里

二、实现方案

  1. 从 resources/media 获取图片的 ArrayBuffer
  2. 将ArrayBuffer转换成PixelMap
  3. pixelMap 生成图片 保存到应用沙箱里
    使用image.createImagePacker()和packer.packToData(pixelMap, packOpts)
  4. 使用fileIo将图片写入到指定沙箱路径
  5. 使用弹窗授权保存媒体库资源(phAccessHelper.showAssetsCreationDialog), 将应用沙箱图片保存到系统相册

三、实践

FileUtil.ets文件代码

export class FileUtil {
	/**
   *
   * @param fileUri 文件的应用沙箱路径
   */
  static deleteFile(fileUri?: string) {
    if (!fileUri) {
      console.log(`沙箱路径 fileUri 参数值 ${fileUri} 不正确`)
      return
    }
    fileIo.access(fileUri, fileIo.AccessModeType.EXIST).then((accessRes: boolean) => {
      if (accessRes) {
        fileIo.unlink(fileUri, (err: BusinessError) => {
          if (err) {
            console.error(`文件:${fileUri} , 删除 失败. Code: ${err.code}, message: ${err.message}`);
          } else {
            console.info(`文件:${fileUri} , 删除 成功`);
          }
        });
      } else {
        console.log(`文件 ${fileUri} 不存在`)
      }
    }).catch((err: BusinessError) => {
      console.error(
        `deleteFile 删除文件 Failed to access. Code: ${err.code}, message: ${err.message} , fileUri: ${fileUri}`);
    });
  }
}

PhotoViewPickerUtil.ets文件代码

import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { common } from '@kit.AbilityKit';
import { fileIo } from '@kit.CoreFileKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { dataSharePredicates } from '@kit.ArkData';
import util from '@ohos.util';
import { FileUtil } from './FileUtil';

export class PhotoViewPickerUtil {
	  // 将已编码的图片 ArrayBuffer 转换为 PixelMap
  static async bufferToPixelMap(buffer: ArrayBuffer): Promise<image.PixelMap | undefined> {
    // 1. 通过 ArrayBuffer 创建 ImageSource
    const imageSource: image.ImageSource = image.createImageSource(buffer);

    // 2. 解码创建 PixelMap
    const pixelMap: image.PixelMap = await imageSource.createPixelMap();

    // 3. 释放 ImageSource 资源
    imageSource.release();

    return pixelMap;
  }

	/**
   * pixelMap 生成图片 保存到应用沙箱里
   * @param uiContext
   * @param pixelMap
   * @param fileName
   */
  static async savaPixelMap(uiContext: common.UIAbilityContext, pixelMap: image.PixelMap,
    fileName?: string): Promise<string | null> {
    const packer = image.createImagePacker();
    const packOpts: image.PackingOption = { format: 'image/png', quality: 100 };
    try {
      const arrayBuffer = await packer.packToData(pixelMap, packOpts);

      if (!fileName) {
        const timeStamp = Date.now();
        // const random = Math.random()
        fileName = "IMG_" + timeStamp + ".png"
      }

      let filePath = `${uiContext.tempDir}/${fileName}`;
      const file = fileIo.openSync(filePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY);
      fileIo.writeSync(file.fd, arrayBuffer);
      fileIo.closeSync(file);
      console.log("pixelMap 生成图片 沙箱路径:", filePath)
      return filePath
    } catch (error) {
      console.error(`pixelMap 生成图片 保存到应用沙箱里 失败, error: ${JSON.stringify(error)}`);
    }
    return null
  }
	/**
	* 使用弹窗授权保存媒体库资源 将应用沙箱图片保存到系统相册
	*/
	static async saveIamgeToPicture(
    srcFileUri: string,
    context: common.UIAbilityContext
  ): Promise<string> {
    console.log("调用了 saveIamgeToPicture")
    let phAccessHelper: photoAccessHelper.PhotoAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
    let desFile: fileIo.File | null = null;
    let srcFile: fileIo.File | null = null;
    try {
      // 指定要保存到应用程序沙盒目录中的图片的URI。
      let srcFileUris: string[] = [
        srcFileUri
      ];
      const timeStamp = Date.now();
      const fileName = "IMG_" + timeStamp
      // 设置要保存的图片的参数:文件扩展名、图片类型、标题和子类型(后两者为可选)
      let photoCreationConfigs: photoAccessHelper.PhotoCreationConfig[] = [
        {
          title: fileName, // This parameter is optional.
          fileNameExtension: 'png',
          photoType: photoAccessHelper.PhotoType.IMAGE,
          subtype: photoAccessHelper.PhotoSubtype.DEFAULT,
        }
      ];

      console.info('沙箱 URI: ' + srcFileUri);
      // 基于弹窗授权获取媒体库中的目标URI
      let desFileUris: string[] =
        await phAccessHelper.showAssetsCreationDialog(srcFileUris, photoCreationConfigs);
      console.info('获取媒体库中的目标 URIs: ' + JSON.stringify(desFileUris));
      // 将图片从沙盒目录写入媒体库中的目标URI。
      desFile = await fileIo.open(desFileUris[0], fileIo.OpenMode.WRITE_ONLY);
      srcFile = await fileIo.open(srcFileUri, fileIo.OpenMode.READ_ONLY);
      await fileIo.copyFile(srcFile.fd, desFile.fd);
      console.info('保存图片成功');
      return '保存图片成功';
    } catch (err) {
      console.error(`保存图片失败 errCode is: ${err.code}, ${err.message}`);
      return `保存图片失败 errCode is: ${err.code}, ${err.message}`;
    } finally {
      if (srcFile) {
        fileIo.closeSync(srcFile);
        FileUtil.deleteFile(srcFileUri)
      }
      if (desFile) {
        fileIo.closeSync(desFile);
      }
    }
  }
}

TestSavaImage.ets文件代码

import { common } from '@kit.AbilityKit';
import resourceManager from '@ohos.resourceManager';
import { PhotoViewPickerUtil } from '../../common/utils/PhotoViewPickerUtil';
import { BusinessError } from '@kit.BasicServicesKit';
import { promptAction } from '@kit.ArkUI';

/*
将 media里的图片保存到相册
 */
@Entry
@ComponentV2
struct TestSavaImage {
  context = this.getUIContext().getHostContext() as common.UIAbilityContext;
  @Local message: string = 'Hello World';

  /**
   * 将 media里的图片保存到相册
   */
  async saveImage() {
    // 1. 从 resources/media 获取图片的 ArrayBuffer
    const mgr: resourceManager.ResourceManager = this.context.resourceManager;
    try {
      const imageBuffer: Uint8Array = await mgr.getMediaContent($r('app.media.enablement_pic2'));
      PhotoViewPickerUtil.bufferToPixelMap(imageBuffer.buffer as ArrayBuffer).then((pixelMap) => {
        if (pixelMap) {
          //保存到沙箱
          PhotoViewPickerUtil.savaPixelMap(this.context, pixelMap).then((filelUri) => {
            if (filelUri) {
              // 保存到相册
              PhotoViewPickerUtil.saveIamgeToPicture(filelUri, this.context).then((res) => {
                promptAction.openToast({ message: res }).catch(() => {

                })
              })
            }
          })
        }
      })
    } catch (error) {
      const err = error as BusinessError
      console.log("保存图片失败 异常信息 name :" + err.name + " , message:" + err.message + " , code:" + err.code)
    }
  }

  build() {
    Column({ space: 20 }) {
      Image($r('app.media.enablement_pic2'))
        .width('90%')
        .objectFit(ImageFit.Contain)
        .margin({ top: 40 })
      Button("将media里的图片保存到相册").onClick(() => {
        this.saveImage()
      })
    }
    .height('100%')
    .width('100%')
  }
}
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐