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、每个条件后面要使用冒号 :,表…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
