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、每个条件后面要使用冒号 :,表…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
