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.鸿蒙南向开发方向

相关推荐
JasonYin~几秒前
HarmonyOS NEXT 实战之元服务:静态案例效果---查看国际航班服务
华为·harmonyos
深海的鲸同学 luvi14 分钟前
【HarmonyOS NEXT】hdc环境变量配置
linux·windows·harmonyos
qystca25 分钟前
洛谷 P11242 碧树 C语言
数据结构·算法
冠位观测者32 分钟前
【Leetcode 热题 100】124. 二叉树中的最大路径和
数据结构·算法·leetcode
XWXnb635 分钟前
数据结构:链表
数据结构·链表
悲伤小伞37 分钟前
C++_数据结构_详解二叉搜索树
c语言·数据结构·c++·笔记·算法
hnjzsyjyj3 小时前
“高精度算法”思想 → 大数阶乘
数据结构·高精度算法·大数阶乘
Freerain996 小时前
鸿蒙Next ArkTS语法适配背景概述
华为·harmonyos
他的猫哎6 小时前
鸿蒙 Navigation组件下的组件获取pageStack问题
harmonyos·鸿蒙
雨汨6 小时前
鸿蒙之路的坑
华为·harmonyos