HarmonyOS 开发-PixelMap深拷贝案例

介绍

在图片开发过程中经常会涉及到PixelMap的深拷贝,本例通过使用PixelMap的readPixelsToBuffer方法来实现深拷贝。在创建源PixelMap的时候,需要将解码参数设置为BGRA_8888,而在深拷贝创建目标PixelMap的时候需要将解码参数设置为RGBA_8888。

效果图预览

使用说明

  1. 进入页面,显示的即为rawfile中图片的PixelMap经过深拷贝过后的PixelMap对象。点击底部的按钮,对原始PixelMap进行深拷贝后再根据相应的比例进行裁剪。点击顶部的保存图标,可以保存当前图片。

实现思路

  1. PixelMap深拷贝方法。通过readPixelsToBuffer读取图片资源的PixelMap到ArrayBuffer,再通过createPixelMap得到目标PixelMap。
typescript 复制代码
   async function copyPixelMap(pm: PixelMap): Promise<PixelMap> {
     const imageInfo: image.ImageInfo = await pm.getImageInfo();
     const buffer: ArrayBuffer = new ArrayBuffer(pm.getPixelBytesNumber());
     // TODO 知识点:通过readPixelsToBuffer实现PixelMap的深拷贝,其中readPixelsToBuffer输出为BGRA_8888
     await pm.readPixelsToBuffer(buffer);
     // TODO 知识点:readPixelsToBuffer输出为BGRA_8888,此处createPixelMap需转为RGBA_8888
     const opts: image.InitializationOptions = {
       editable: true,
       pixelFormat: image.PixelMapFormat.RGBA_8888,
       size: { height: imageInfo.size.height, width: imageInfo.size.width }
     };
     return await image.createPixelMap(buffer, opts);
   }
  1. 初始化时,通过深拷贝从原始PixelMap创建目标PixelMap。源码参考ImageDepthCopy.ets
typescript 复制代码
   async aboutToAppear(): Promise<void> {
     const context: Context = getContext(this);
     // 获取resourceManager资源管理
     const resourceMgr: resourceManager.ResourceManager = context.resourceManager;
     // 获取rawfile中的图片资源
     const fileData: Uint8Array = await resourceMgr.getRawFileContent(ImageCropConstants.RAWFILE_PICPATH);
     // 获取图片的ArrayBuffer
     const buffer = fileData.buffer.slice(fileData.byteOffset, fileData.byteLength + fileData.byteOffset);
     // 保存用于恢复原图的imageSource
     this.imageSource = image.createImageSource(buffer);
     // TODO 知识点: 创建源图片的用于深拷贝的PixelMap,因readPixelsToBuffer输出为BGRA_8888。故此处desiredPixelFormat需为BGRA_8888
     const decodingOptions: image.DecodingOptions = {
       editable: false, // 是否可编辑。当取值为false时,图片不可二次编辑。
       desiredPixelFormat: image.PixelMapFormat.BGRA_8888,
     }
     // 保存用于深拷贝的pixelMap
     this.pixelMapSrc = await this.imageSource.createPixelMap(decodingOptions);
     // TODO 知识点: 通过readPixelsToBuffer进行深拷贝
     this.pixelMapDst = await copyPixelMap(this.pixelMapSrc!);
   }
  1. 图片裁剪。源码参考ImageDepthCopy.ets
typescript 复制代码
    ...
    // TODO 知识点:通过readPixelsToBuffer拷贝到PixelMap对象
    const pixelMapTemp = await copyPixelMap(this.pixelMapSrc);
    const imageInfo: image.ImageInfo = await pixelMapTemp.getImageInfo();
    if (!imageInfo) {
      logger.error(TAG, `imageInfo is null`);
      return;
    }
    let imageHeight: number = imageInfo.size.height;
    let imageWith: number = imageInfo.size.width;
    if (proportion === ImageCropConstants.ONE_ONE) {
      if (imageHeight > imageWith) {
        imageHeight = imageWith;
      } else {
        imageWith = imageHeight;
      }
    }
    try {
      logger.info(TAG, `imageInfo imageHeight = ${JSON.stringify(imageHeight / proportion)}, imageWith = ${JSON.stringify(imageWith)}`);
      // PixelMap按比例裁剪
      await pixelMapTemp.crop({
        size: { height: imageHeight / proportion, width: imageWith },
        x: 0,
        y: 0
      });
      this.pixelMapDst = pixelMapTemp;
    } catch (error) {
      logger.error(TAG, `imageInfo crop error = ${JSON.stringify(error)}`);
    }
  1. 保存图片。将裁剪后的图片保存。源码参考FileUtil.ets
typescript 复制代码
   export async function savePixelMap(context: Context, pm: PixelMap): Promise<string> {
     if (pm === null) {
       logger.error(TAG, '传入的pm为空');
       return '';
     }
     const imagePackerApi: image.ImagePacker = image.createImagePacker();
     const packOpts: image.PackingOption = { format: 'image/jpeg', quality: 30 };
     try {
       packToFile(context, pm);
       const data: ArrayBuffer = await imagePackerApi.packing(pm, packOpts);
       return await saveFile(context, data);
     } catch (err) {
       logger.error(TAG, '保存文件失败,err=' + JSON.stringify(err));
       return '';
     }
   }
   
   async function saveFile(context: Context, data: ArrayBuffer): Promise<string> {
     let uri: string = context.filesDir + '/' + getTimeStr() + '.jpg';
     const file: fileIo.File = fs.openSync(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
     fs.writeSync(file.fd, data);
     fs.closeSync(file);
     // 加上file://前缀
     uri = 'file:/' + uri;
     return uri;
   }

工程结构&模块类型

   imagedepthcopy                               // har类型
   |---view
   |   |---ImageDepthCopy.ets                   // 视图层-图片深拷贝页面
   |---constants
   |   |---ImageCropConstants.ets               // 常量
   |---model
   |   |---AdjustData.ets                       // 裁剪选项资源
   |---util
   |   |---CopyObj.ets                          // 业务层-图片深拷贝处理
   |   |---FileUtil.ets                         // 业务层-图片保存

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ......

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ......

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ......

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题

2.性能优化方向

3.架构方向

4.鸿蒙开发系统底层方向

5.鸿蒙音视频开发方向

6.鸿蒙车载开发方向

7.鸿蒙南向开发方向

相关推荐
踏雪Vernon3 小时前
[OpenHarmony5.0][Docker][环境]OpenHarmony5.0 Docker编译环境镜像下载以及使用方式
linux·docker·容器·harmonyos
Hera_Yc.H6 小时前
数据结构之一:复杂度
数据结构
肥猪猪爸7 小时前
使用卡尔曼滤波器估计pybullet中的机器人位置
数据结构·人工智能·python·算法·机器人·卡尔曼滤波·pybullet
linux_carlos7 小时前
环形缓冲区
数据结构
Andy醒7 小时前
HarmonyOS . 沉浸状态栏使用
harmonyos·鸿蒙
readmancynn7 小时前
二分基本实现
数据结构·算法
yuwinter7 小时前
鸿蒙HarmonyOS学习笔记(2)
笔记·学习·harmonyos
Bucai_不才7 小时前
【数据结构】树——链式存储二叉树的基础
数据结构·二叉树
盼海7 小时前
排序算法(四)--快速排序
数据结构·算法·排序算法