HarmonyOS开发实战( Beta5.0)图片编辑实现马赛克效果详解
鸿蒙HarmonyOS开发往期必看:
HarmonyOS NEXT应用开发性能实践总结
最新版!“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线!(从零基础入门到精通)
介绍
本示例将原图手指划过的区域分割成若干个大小一致的小方格,然后获取每个小方格中的像素点的平均色彩数值,使用获取到的平均色彩数值替换该方格中所有的像素点。最后使用createPixelMapSync接口将新的像素点数据写入图片,即可实现原始图片的局部马赛克处理。
效果图预览

使用说明
- 进入页面,手指划过图片的某一个区域即可将该区域马赛克处理。点击底部的“恢复原图”按钮,将恢复为原图。
实现思路
-
获取原始图片信息,将原始图片设置为可编辑状态。
/** * 获取图片内容 */ @Concurrent async function getImageContent(imgPath: string, context: Context): Promise<Uint8Array | undefined> {// 获取resourceManager资源管理const resourceMgr: resourceManager.ResourceManager = context.resourceManager;// 获取rawfile中的图片资源const fileData: Uint8Array = await resourceMgr.getRawFileContent(imgPath);return fileData; }/** * 获取原始图片信息 */ async getSrcImageInfo(): Promise<void> {// TODO: 性能知识点:使用new taskpool.Task()创建任务项,传入获取图片内容函数和所需参数const task: taskpool.Task = new taskpool.Task(getImageContent, MosaicConstants.RAWFILE_PICPATH, getContext(this));try {const fileData: Uint8Array = await taskpool.execute(task) as Uint8Array;// 获取图片的ArrayBufferconst buffer = fileData.buffer.slice(fileData.byteOffset, fileData.byteLength + fileData.byteOffset);// 获取原图imageSourcethis.imageSource = image.createImageSource(buffer);// TODO 知识点: 将图片设置为可编辑const decodingOptions: image.DecodingOptions = {editable: true,desiredPixelFormat: image.PixelMapFormat.RGBA_8888,}// 创建PixelMapthis.pixelMapSrc = await this.imageSource.createPixelMap(decodingOptions);} catch (err) {console.error("getSrcImageInfo: execute fail, err:" + (err as BusinessError).toString());} } -
保存图片的原始尺寸及在屏幕的显示区域。
// 读取图片信息const imageInfo: image.ImageInfo = await this.pixelMapSrc!.getImageInfo();// 获取图片的宽度和高度this.imageWidth = imageInfo.size.width;this.imageHeight = imageInfo.size.height;// 获取屏幕尺寸const displayData: display.Display = display.getDefaultDisplaySync();// 计算图片的显示尺寸this.displayWidth = px2vp(displayData.width);this.displayHeight = this.displayWidth * this.imageHeight / this.imageWidth; -
获取手指按下和移动时的坐标,手指移动时执行马赛克任务。
PanGesture().onActionStart((event: GestureEvent) => {const finger: FingerInfo = event.fingerList[0];if (finger == undefined) {return;}this.startX = finger.localX;this.startY = finger.localY;}).onActionUpdate((event: GestureEvent) => {const finger: FingerInfo = event.fingerList[0];if (finger == undefined) {return;}this.endX = finger.localX;this.endY = finger.localY;// 执行马赛克任务await this.doMosaicTask(this.startX, this.startY, this.endX, this.endY);this.startX = this.endX;this.startY = this.endY;}) -
在马赛克任务中处理坐标转换问题后执行马赛克处理函数applyMosaic。
async doMosaicTask(offMinX: number, offMinY: number, offMaxX: number, offMaxY: number): Promise<void> {// TODO 知识点:将手势移动的起始坐标转换为原始图片中的坐标offMinX = Math.round(offMinX * this.imageWidth / this.displayWidth);offMinY = Math.round(offMinY * this.imageHeight / this.displayHeight);offMaxX = Math.round(offMaxX * this.imageWidth / this.displayWidth);offMaxY = Math.round(offMaxY * this.imageHeight / this.displayHeight);// 处理起始坐标大于终点坐标的情况if (offMinX > offMaxX) {const temp = offMinX;offMinX = offMaxX;offMaxX = temp;}if (offMinY > offMaxY) {const temp = offMinY;offMinY = offMaxY;offMaxY = temp;}// 获取像素数据的字节数const bufferData = new ArrayBuffer(this.pixelMapSrc!.getPixelBytesNumber());await this.pixelMapSrc!.readPixelsToBuffer(bufferData);// 将像素数据转换为 Uint8Array 便于像素处理let dataArray = new Uint8Array(bufferData);// TODO: 性能知识点:使用new taskpool.Task()创建任务项,传入任务执行函数和所需参数const task: taskpool.Task =new taskpool.Task(applyMosaic, dataArray, this.imageWidth, this.imageHeight, MosaicConstants.BLOCK_SIZE,offMinX, offMinY, offMaxX, offMaxY);try {taskpool.execute(task, taskpool.Priority.HIGH).then(async (res: Object) => {this.pixelMapSrc = image.createPixelMapSync((res as Uint8Array).buffer, this.opts);this.isMosaic = true;})} catch (err) {console.error("doMosaicTask: execute fail, " + (err as BusinessError).toString());}
}
-
实现图像局部马赛克处理函数
async applyMosaic(dataArray: Uint8Array, imageWidth: number, imageHeight: number, blockSize: number,offMinX: number, offMinY: number, offMaxX: number, offMaxY: number): Promise<Uint8Array | undefined> {try {// 计算横排和纵排的块数let xBlocks = Math.floor((Math.abs(offMaxX - offMinX)) / blockSize);let yBlocks = Math.floor((Math.abs(offMaxY - offMinY)) / blockSize);logger.info(MosaicConstants.TAG, 'xBlocks: ' + xBlocks.toString() + ' ,yBlocks:' + yBlocks.toString());// 不足一块的,按一块计算if (xBlocks < 1) {xBlocks = 1;offMaxX = offMinX + blockSize;}if (yBlocks < 1) {yBlocks = 1;offMaxY = offMinY + blockSize;}// 遍历每个块for (let y = 0; y < yBlocks; y++) {for (let x = 0; x < xBlocks; x++) {const startX = x * blockSize + offMinX;const startY = y * blockSize + offMinY;// 计算块内的平均颜色let totalR = 0;let totalG = 0;let totalB = 0;let pixelCount = 0;for (let iy = startY; iy < startY + blockSize && iy < imageHeight && iy < offMaxY; iy++) {for (let ix = startX; ix < startX + blockSize && ix < imageWidth && ix < offMaxX; ix++) {// TODO 知识点:像素点数据包括RGB通道的分量值及图片透明度const index = (iy * imageWidth + ix) * 4; // 4 像素点数据包括RGB通道的分量值及图片透明度totalR += dataArray[index];totalG += dataArray[index + 1];totalB += dataArray[index + 2];pixelCount++;}}const averageR = Math.floor(totalR / pixelCount);const averageG = Math.floor(totalG / pixelCount);const averageB = Math.floor(totalB / pixelCount);// TODO 知识点: 将块内平均颜色应用到块内的每个像素for (let iy = startY; iy < startY + blockSize && iy < imageHeight && iy < offMaxY; iy++) {for (let ix = startX; ix < startX + blockSize && ix < imageWidth && ix < offMaxX; ix++) {const index = (iy * imageWidth + ix) * 4; // 4 像素点数据包括RGB通道的分量值及图片透明度dataArray[index] = averageR;dataArray[index + 1] = averageG;dataArray[index + 2] = averageB;}}}}return dataArray;} catch (error) {logger.error(MosaicConstants.TAG, 'applyMosaic fail,err:' + error);return undefined;} }
高性能知识点
本示例使用了taskpool执行耗时操作以达到性能优化。
工程结构&模块类型
imagemosaic // har类型
|---view
| |---ImageMosaicView.ets // 视图层-图片马赛克场景
|---constants
| |---MosaicConstants.ets // 常量
模块依赖
本示例依赖common模块来实现日志的打印、动态路由模块来实现页面的动态加载。
最后
小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,不同的角度的问了一些问题,我明显感觉到一点,那就是许多人参与鸿蒙开发,但是又不知道从哪里下手,因为体系杂乱无章,教授的人也多,无从选择。有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)路线、视频、文档用来跟着学习是非常有必要的。
如果你是一名有经验的资深Android移动开发、Java开发、前端开发、对鸿蒙感兴趣以及转行人员
鸿蒙 NEXT 全栈开发学习笔记 希望这一份鸿蒙学习文档能够给大家带来帮助~
鸿蒙(HarmonyOS NEXT)最新学习路线
该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级设备开发,不仅补充了华为官网未涉及的解决方案
路线图适合人群:
IT开发人员:想要拓展职业边界
零基础小白:鸿蒙爱好者,希望从0到1学习,增加一项技能。
技术提升/进阶跳槽:发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术
2.视频教程+学习PDF文档
(鸿蒙语法ArkTS、TypeScript、ArkUI教程……)

纯血版鸿蒙全套学习文档(面试、文档、全套视频等)

鸿蒙APP开发必备
总结
参与鸿蒙开发,你要先认清适合你的方向,如果是想从事鸿蒙应用开发方向的话,可以参考本文的学习路径,简单来说就是:为了确保高效学习,建议规划清晰的学习路线
相关文章:
HarmonyOS开发实战( Beta5.0)图片编辑实现马赛克效果详解
鸿蒙HarmonyOS开发往期必看: HarmonyOS NEXT应用开发性能实践总结 最新版!“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线!(从零基础入门到精通) 介绍 本示例将原图手指划过的区域分割成若干个大小一致的小方格…...
【新书介绍】《JavaScript前端开发与实例教程(微课视频版)(第2版)》
本书重点 无任何基础的初学者,高校JavaScript课程教材。 配套非常全,提供案例源代码、PPT课件、课后习题答案、微课视频、教案、教学大纲、课程实训、期末考试试卷、章节测试、实验报告、学习通建课资源包。 内容简介 JavaScript是开发Web前端必须掌…...
什么是GWAS全基因组关联分析?
什么是全基因组关联分析?(Genome-Wide Association Study,GWAS) 全基因组关联分析(GWAS)是一种在全基因组范围内搜索遗传变异(通常是单核苷酸多态性,SNP)与复杂性状之间关…...
k8s dashboard token 生成/获取
创建示例用户 在本指南中,我们将了解如何使用 Kubernetes 的服务帐户机制创建新用户、授予该用户管理员权限并使用与该用户绑定的承载令牌登录仪表板。 对于以下每个和的代码片段ServiceAccount,ClusterRoleBinding您都应该将它们复制到新的清单文件(如)…...
windows@openssh免密登陆配置@基于powershell快速配置脚本
文章目录 abstract免密自动登录配置介绍👺修改Server配置文件一键脚本修改👺 向ssh server端上传或创建支持免密登录的公钥文件预执行命令👺方式1方式2重启服务以生效👺 傻瓜式配置免密自动登录👺👺准备 操…...
【深度学习】【图像分类】【OnnxRuntime】【Python】VggNet模型部署
【深度学习】【图像分类】【OnnxRuntime】【Python】VggNet模型部署 提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 【深度学习】【图像分类】【OnnxRuntime】【Python】VggNet模型部署前言Windows平台搭建依赖环境模型转换--pytorch转onnxONN…...
手写排班日历
手写排班日历: 效果图: vue代码如下: <template><div class"YSPB"><div class"title">排班日历</div><div class"banner"><span classiconfont icon-youjiantou click&qu…...
SpringBoot多数据源配置
1、添加依赖 <!-- 数据库驱动 --><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql-connector-java.version}</version><scope>runtime</sco…...
影响画布微信小程序canvas及skyline和webview用户界面布局的关键流程
影响微信小程序画布canvas及skyline和webview用户界面布局的关键流程 目录 影响微信小程序画布canvas及skyline和webview用户界面布局的关键流程 一、微信小程序canvas开发流程 1.1、官方指南 1.2、客制化开发 第一步:在 WXML 中添加 canvas 组件 第二步&…...
MATLAB图像处理
MATLAB图像处理 MATLAB,作为美国MathWorks公司出品的商业数学软件,以其强大的矩阵运算能力和丰富的函数库,在图像处理领域得到了广泛的应用。MATLAB不仅提供了基础的图像处理功能,还通过图像处理工具箱(Image Process…...
【编程底层思考】性能监控和优化:JVM参数调优,诊断工具的使用等。JVM 调优和线上问题排查实战经验总结
JVM性能监控和优化是确保Java应用程序高效运行的关键环节。以下是一些JVM性能监控和优化的方法,以及使用诊断工具和实战经验的总结: 一、JVM参数调优: 堆大小设置 : - Xms:设置JVM启动时的初始堆大小。 - -Xmx:设置J…...
数据库的实施过程分析
在完成了数据库的逻辑结构设计和物理结构设计后,下一步就是将设计成果转化为现实,这一步骤被称为数据库的实施。数据库实施是数据库开发过程中至关重要的一环,它标志着从设计阶段向实际应用的过渡。本文将为你详细讲解数据库实施的各个关键步…...
【Kubernetes】常见面试题汇总(十二)
目录 36.简述 Kubernetes 的负载均衡器? 37.简述 Kubernetes 各模块如何与 APl Server 通信? 38.简述 Kubernetes Scheduler 作用及实现原理? 36.简述 Kubernetes 的负载均衡器? (1)负载均衡器是暴露服务…...
基于SpringBoot+Vue+MySQL的美术馆管理系统
系统展示 用户前台界面 管理员后台界面 系统背景 随着文化艺术产业的蓬勃发展,美术馆作为展示与传播艺术的重要场所,其管理工作变得日益复杂。为了提升美术馆的运营效率、优化参观体验并加强艺术品管理,我们开发了基于SpringBootVueMySQL的美…...
golang面试
算法: 1.提取二进制位最右边的 r i & (~i 1) 2.树上两个节点最远距离,先考虑头结点参与不参与。 3.暴力递归改dp。 1.确定暴力递归方式。 2.改记忆化搜索 3.严格表方式: 分析可变参数变化范围,参数数量决定表维度、 …...
基于"WT2605C的智能血压计:AI对话引领个性化健康管理新时代,健康守护随时在线
在当今快节奏的生活中,健康管理已成为我们日常不可或缺的一部分。随着科技的进步,智能设备正逐步融入我们的日常生活,为健康管理带来前所未有的便捷与智能化。今天,让我们共同探索WT2605C AI在线方案如何在血压计中发挥革命性作用…...
redis高级教程
一 关系型数据库和 NoSQL 数据库 数据库主要分为两大类:关系型数据库与 NoSQL 数据库 关系型数据库 ,是建立在关系模型基础上的数据库,其借助于集合代数等数学概念和方法来处理数据库中的数据主流的 MySQL 、 Oracle 、 MS SQL Server 和 D…...
prfm命令初探
1. 前言 在查看一段neon代码时,发现有如下片段,为使用汇编进行数据预取操作。这是一个新的知识点,记录一下学习过程。 __asm__ volatile("prfm pldl2keep,[%0, #8192] \n""prfm pldl1keep,[%0, #1024] \n":"r"…...
AI大模型需要学什么?怎么学?从零基础入门大模型(保姆级),从这开始出发!
一.初聊大模型 1.为什么要学习大模型? 在学习大模型之前,你不必担心自己缺乏相关知识或认为这太难。我坚信,只要你有学习的意愿并付出努力,你就能够掌握大模型,并能够用它们完成许多有意义的事情。在这个快速变化的时代…...
python自述3
Python 条件控制 if语句的一般形式如下所示: if condition_1: statement_block_1 elif condition_2: statement_block_2 else: statement_block_3 Python 中用 elif 代替了 else if,所以if语句的关键字为:if – elif – else。 注意: 1、每个条件后面要使用冒号 :,表…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)
LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 题目描述解题思路Java代码 题目描述 题目链接:LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...
spring Security对RBAC及其ABAC的支持使用
RBAC (基于角色的访问控制) RBAC (Role-Based Access Control) 是 Spring Security 中最常用的权限模型,它将权限分配给角色,再将角色分配给用户。 RBAC 核心实现 1. 数据库设计 users roles permissions ------- ------…...
恶补电源:1.电桥
一、元器件的选择 搜索并选择电桥,再multisim中选择FWB,就有各种型号的电桥: 电桥是用来干嘛的呢? 它是一个由四个二极管搭成的“桥梁”形状的电路,用来把交流电(AC)变成直流电(DC)。…...
