目录

如何实现解码Base64字符串格式图片为PixelMap并保存入系统图库

问题现象

如何将Base64字符串格式的图片解码为PixelMap,并保存至系统图库中。

背景知识

解决方案

完整示例参考如下:

import { Context } from '@kit.AbilityKit';
import { util } from '@kit.ArkTS';
import image from '@ohos.multimedia.image';
import { fileIo, fileUri } from '@kit.CoreFileKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';

@Entry
@Component
struct Base64ImageDemo {
  @State imageStr: string = '';
  @State pixelMap: image.PixelMap | undefined = undefined;

  async image2Base64Str() {
    let imageSource: image.ImageSource | undefined = undefined;
    try {
      // 读取rawfile目录下的图片文件
      let context = this.getUIContext().getHostContext() as Context;
      let imgData = await context.resourceManager.getRawFileContent('img.png');
      // 获取图片mime type
      imageSource = image.createImageSource(imgData.buffer.slice(0));
      let info = await imageSource.getImageInfo();
      let mime = info.mimeType;
      // 编码图片数据为base64字符串
      let base64Helper = new util.Base64Helper();
      let base64Str = await base64Helper.encodeToString(imgData);
      this.imageStr = `data:${mime};base64,` + base64Str;
    } catch (err) {
      console.info(`Failed to encode image data to base64: ${JSON.stringify(err)}`);
    } finally {
      if (imageSource) {
        await imageSource.release();
      }
    }
  }

  async base64Str2PixelMap() {
    let imageSource: image.ImageSource | undefined = undefined;
    try {
      // 判断是否以固定格式开头,如果不是则为非法base64字符串图片
      let headerReg = new RegExp('data:image/\\w+;base64,');
      let idx = this.imageStr.search(headerReg);
      if (idx !== 0) {
        console.error(`Invalid image base64 string`);
        return;
      }
      // 去除头部固定格式字符串
      let base64Str = this.imageStr.replace(headerReg, '');
      // 解码base64为图片二进制数据
      let base64Helper = new util.Base64Helper();
      let imgData = await base64Helper.decode(base64Str);
      // 通过图片二进制数据创建ImageSource,并解码为PixelMap
      imageSource = image.createImageSource(imgData.buffer.slice(0));
      this.pixelMap = await imageSource.createPixelMap();
    } catch (err) {
      console.error(`Failed to decode base64 string to pixelmap: ${JSON.stringify(err)}`);
    } finally {
      if (imageSource) {
        await imageSource.release();
      }
    }
  }


  async saveBase64StrImage() {
    // 匹配开头固定格式的字符串,若不存在,则为非法base64图片
    let headerReg = new RegExp('data:image/\\w+;base64,');
    let matchArr = this.imageStr.match(headerReg);
    if (!matchArr || matchArr.length === 0) {
      console.error(`Invalid image base64 string`);
      return;
    }
    // 去除头部固定格式的字符串
    let base64Str = this.imageStr.replace(headerReg, '');
    // 获得图片编码格式信息
    let fileNameExtension = matchArr[0].replace('data:image/', '').replace(';base64,', '');
    // 解码base64为图片二进制数据
    let base64Helper = new util.Base64Helper();
    let imgData = await base64Helper.decode(base64Str);
    // 写入沙箱文件
    let context = this.getUIContext().getHostContext() as Context;
    let srcFilePath = context.tempDir + `/temp_img.${fileNameExtension}`;
    let tmpFile: fileIo.File | undefined = undefined;
    try {
      tmpFile = fileIo.openSync(srcFilePath, fileIo.OpenMode.WRITE_ONLY | fileIo.OpenMode.CREATE);
      fileIo.writeSync(tmpFile.fd, imgData.buffer.slice(0));
    } catch (err) {
      console.error(`Failed to write image data to sandbox: ${JSON.stringify(err)}`);
      return;
    } finally {
      if (tmpFile) {
        fileIo.closeSync(tmpFile);
      }
    }

    let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
    let srcFile: fileIo.File | undefined = undefined;
    let desFile: fileIo.File | undefined = undefined;
    try {
      srcFile = await fileIo.open(srcFilePath, fileIo.OpenMode.WRITE_ONLY);
      let srcFileUri = fileUri.getUriFromPath(srcFilePath);
      let srcFileUris: Array<string> = [
        srcFileUri,
      ];
      // 指定待保存照片的创建选项,包括文件后缀和照片类型,标题和照片子类型可选。
      let photoCreationConfigs: Array<photoAccessHelper.PhotoCreationConfig> = [
        {
          fileNameExtension: fileNameExtension,
          photoType: photoAccessHelper.PhotoType.IMAGE,
        },
      ];
      // 基于弹窗授权的方式获取媒体库的目标uri。
      let desFileUris: Array<string> =
        await phAccessHelper.showAssetsCreationDialog(srcFileUris, photoCreationConfigs);
      // 将来源于应用沙箱的照片内容写入媒体库的目标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('create asset by dialog successfully');
    } catch (err) {
      console.error(`Error: ${JSON.stringify(err)}`);
    } finally {
      if (srcFile) {
        await fileIo.close(srcFile);
      }
      if (desFile) {
        await fileIo.close(desFile);
      }
    }
  }


  build() {
    Column({ space: 20 }) {
      Button('Image2Base64')
        .fontSize(30)
        .onClick(async () => {
          await this.image2Base64Str();
        });

      Button('Base64Str2PixelMap')
        .fontSize(30)
        .onClick(async () => {
          await this.base64Str2PixelMap();
        });

      Button('SaveBase64StrImage')
        .fontSize(30)
        .onClick(async () => {
          await this.saveBase64StrImage();
        });

      Image(this.imageStr)
        .width('50%')
        .aspectRatio(1)
        .objectFit(ImageFit.Contain);

      Image(this.pixelMap)
        .width('50%')
        .aspectRatio(1)
        .objectFit(ImageFit.Contain);
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center);
  }
}