bitArt 系列 01:架构
最近整理一个 HarmonyOS 像素画编辑器项目 bitArt发现它很适合作为复杂 ArkTS 应用的拆解案例。它不是一个只有按钮和列表的 Demo而是一个完整的移动端创作工具中间是像素画布周围有工具栏、图层面板、调色板、动画帧时间轴、项目管理、导入导出和设置。这篇先不急着讲某一个算法而是从整体架构看它如何把复杂编辑器拆开。源码路径是D:\HM\bitArt核心代码集中在entry/src/main/ets。1. 为什么编辑器应用不能只写在页面里像素画编辑器看起来是 UI 密集型应用但真正麻烦的地方不是按钮多而是状态多。一个用户在画布上移动手指时应用至少要处理这些事判断当前工具是铅笔、橡皮、填充、取色、形状还是移动。把触控坐标转换成像素坐标。判断当前图层是否锁定。修改当前图层的像素矩阵。重新合成可见图层。更新画布渲染。记录撤销快照。标记项目已修改等待自动保存。如果时间轴打开还要同步当前帧。如果这些逻辑全部塞进一个页面的 UI 构建代码里页面会很快变成一个几千行的状态泥潭。bitArt 当前把入口、工作区组件和领域服务分开Index.ets只处理页面可见性并挂载工作区BitArtEditorWorkspace.ets负责状态编排具体行为继续下沉到services/。项目核心目录大致是entry/src/main/ets/ pages/ Index.ets components/editor/ BitArtEditorWorkspace.ets PixelCanvasView.ets models/ EditorModels.ets services/ PixelCanvasService.ets PixelCanvasRendererService.ets LayerCanvasService.ets LayerStackService.ets EditorCanvasDrawingWorkflowService.ets EditorHistoryWorkflowService.ets EditorFrameService.ets EditorPersistenceService.ets EditorExportService.ets ImageImportService.ets这个拆分的好处是非常直接的画布算法、图层算法、帧算法、保存算法都可以独立阅读和测试。页面不需要知道“一个 GIF 怎么编码”也不需要知道“source-over 混合公式怎么写”它只需要调用服务层拿到新的状态。2. 工作区组件BitArtEditorWorkspace 是状态编排器Index.ets当前是一个很薄的页面壳页面出现或隐藏时更新editorPageVisiblebuild()中只挂载BitArtEditorWorkspace()。真正持有当前工具、颜色、图层、帧、画布尺寸、面板开合、撤销栈和项目列表的是BitArtEditorWorkspace.ets。例如工作区组件初始化图层和帧时并不手工拼像素数组const INITIAL_LAYERS_PIXELS: string[][] LayerCanvasService.createInitialLayers(LAYERS, DEFAULT_CANVAS_SIZE, DEFAULT_CANVAS_SIZE); const INITIAL_FRAMES: EditorFrame[] EditorFrameService.createInitialFrames(LAYERS, INITIAL_LAYERS_PIXELS, layer-1);这段代码背后的设计点是页面不直接制造像素矩阵而是把“初始图层应该是什么样”交给LayerCanvasService把“第一帧应该如何复制图层数据”交给EditorFrameService。换句话说BitArtEditorWorkspace更像一个工作台调度器它决定当前展示哪些面板。它把用户操作转换成服务层调用。它接收服务返回的新状态。它触发 UI 刷新、保存和导出。这种拆分对编辑器应用很重要。因为编辑器的功能会持续增长如果页面从一开始就承担所有业务细节后面新增图层合并、动画帧、GIF 导出时代码会很难维护。3. 组件层PixelCanvasView 专心处理画布交互bitArt 把真正的 Canvas 组件放到了components/editor/PixelCanvasView.ets。这个组件关注的是“画布如何显示”和“触摸如何转成像素坐标”。它接收像素数据、画布宽高、缩放比例、脏区域边界等属性Prop Watch(handlePixelsChange) pixels: string[] []; Prop Watch(redraw) gridVisible: boolean true; Prop Watch(handleCanvasSizeChange) canvasWidth: number 24; Prop Watch(handleCanvasSizeChange) canvasHeight: number 24; Prop Watch(handleDirtyVersionChange) dirtyVersion: number 0; Prop dirtyMinRow: number 0; Prop dirtyMinCol: number 0; Prop dirtyMaxRow: number 0; Prop dirtyMaxCol: number 0;这里有一个值得借鉴的点组件没有自己去管理项目、图层、帧它只认最终要画出来的pixels。这样 Canvas 组件就可以保持纯粹复用成本也更低。用户触摸画布时组件把屏幕坐标转换成像素行列再通过回调通知页面private getTouchCell(event: TouchEvent): CanvasCell { const x event.touches[0].x - this.getDrawLeft(); const y event.touches[0].y - this.getDrawTop(); return { row: EditorViewportService.positionToCell(y, drawHeight, this.canvasHeight), col: EditorViewportService.positionToCell(x, drawWidth, this.canvasWidth), valid: true }; }组件层只负责把“用户点了哪里”说清楚至于点下去以后是画笔、橡皮、填充还是取色交给上层状态和服务层决定。4. 服务层复杂逻辑按领域拆开bitArt 的services/是项目最值得看的一层。几个核心服务的职责如下服务职责PixelCanvasService单层像素矩阵操作负责画笔、橡皮、填充、形状、取色PixelCanvasRendererServiceCanvas 渲染负责网格、脏区域、像素柔化和同色连续段批绘LayerCanvasService多图层像素合成负责透明度混合和局部合成LayerStackService图层栈操作负责新增、删除、复制、锁定、合并EditorFrameService动画帧操作负责帧复制、删除、时长归一化EditorPersistenceService项目持久化负责 manifest 和项目 JSON自动保存时机由会话工作流控制EditorExportService图片导出负责 PNG/JPG/GIF 和相册写入ImageImportService图片导入负责相册选择、解码、缩放和转像素矩阵这个服务划分的关键是“按领域而不是按按钮拆”。比如图层面板上可能有删除、复制、锁定、透明度调整等多个按钮但它们都属于图层栈行为所以统一放在LayerStackService。5. 模型层让状态可以保存、恢复和撤销bitArt 的模型集中在EditorModels.ets。核心模型包括export interface EditorFrame { id: string; name: string; durationMs: number; layers: LayerItem[]; layersPixels: string[][]; activeLayer: string; } export interface EditorPersistentProject { schemaVersion: number; projectId: string; projectName: string; canvasWidth?: number; canvasHeight?: number; activeTool: string; activeLayer: string; activeFrame: string; frames: EditorFrame[]; layers: LayerItem[]; layersPixels: string[][]; undoStack: EditorSnapshot[]; redoStack: EditorSnapshot[]; }这里可以看到一个重要选择帧不是只保存一张预览图而是保存完整的layers和layersPixels。这意味着每一帧都有独立图层结构动画编辑不会和当前画布状态混在一起。对于编辑器来说这种数据完整性比省一点内存更重要。否则切换帧、复制帧、导出 GIF 时很容易出现“当前画面和帧数据不同步”的问题。6. 系统能力层HarmonyOS API 的落点bitArt 用到的 HarmonyOS 能力主要集中在几个地方kit.AbilityKit拿到UIAbilityContext用于文件路径和应用上下文。kit.CoreFileKit读写项目 JSON、缓存导出图片。ohos.multimedia.image创建 PixelMap、编码 PNG/JPG。ohos.file.photoAccessHelper选择图片、写入系统相册。AppStorage同步安全区、持久化触发信号等跨层状态。这种系统 API 不直接散落在页面里的做法也很稳。比如保存项目时只需要看EditorPersistenceService导出图片时只需要看EditorExportService。后续如果 HarmonyOS API 有变化修改范围也更明确。7. 怎么判断分层没有停留在目录表面文件分得多不等于架构清晰。验证 bitArt 的分层可以沿一条真实操作向下追踪用户在画布落笔后PixelCanvasView只上报触控位置绘制工作流决定当前工具和脏区域像素服务修改活动层图层服务更新合成结果工作区负责替换状态、记录历史并标记项目已修改。每一层都有输入和输出没有让 Canvas 组件直接写项目文件也没有让持久化服务反过来操作 UI。再检查几个跨模块动作切换动画帧前是否同步工作区图层导出前是否结束笔触并强制保存恢复项目后是否重新建立活动帧和活动图层锁定图层后绘制工作流是否在修改像素前拦截。只要这些路径能顺着服务边界走完分层才真正参与了行为控制而不只是把长文件拆成多个短文件。8. 这个架构最值得借鉴的点我认为 bitArt 的整体设计有三个经验可以复用到其他 HarmonyOS 应用。第一页面层不要吞掉业务层。复杂应用早期看起来可以靠一个页面撑住但状态一多维护成本会急剧上升。第二编辑器应用要先定义数据所有权。bitArt 让项目、帧、图层、像素矩阵都有明确归属之后撤销、保存、导出才能顺畅接上。第三高频交互要单独设计渲染路径。像素画布不是普通列表它有连续触摸、缩放、平移、局部刷新和网格渲染。如果直接依赖全量刷新体验很快会掉下来。这一篇主要把项目全貌铺开。下一篇会继续拆EditorModels.ets和EditorCanvasService.ets看一个像素画编辑器的数据模型如何设计尤其是为什么 bitArt 选择LayerItem[] string[][]这种结构来承载图层像素。

相关新闻

蓝牙5.4音频模块开发实战:低功耗LC3编码与射频设计

蓝牙5.4音频模块开发实战:低功耗LC3编码与射频设计

1. 项目背景与核心组件选型在无线音频传输领域,蓝牙5.4标准的推出标志着LE Audio技术正式进入实用阶段。我们选择的IDC777-1模块作为射频前端,搭配STM32L152RE主控的方案,能够实现专业级无线音频传输质量。这套组合的核心优势在于&#xff1a…

2026/7/13 6:35:41阅读更多 →
TLA2518与PIC18F24K50构建高精度数据采集系统

TLA2518与PIC18F24K50构建高精度数据采集系统

1. TLA2518与PIC18F24K50的硬件协同设计在工业测量和嵌入式系统中,模拟信号到数字信号的可靠转换是数据采集的核心环节。TLA2518作为TI推出的12位精度SAR型ADC芯片,与Microchip的PIC18F24K50单片机组合,能够构建高性价比的信号采集系统。这套…

2026/7/13 6:35:41阅读更多 →
STM32F446RE GPIO上拉下拉配置与DTH-08模块接口设计

STM32F446RE GPIO上拉下拉配置与DTH-08模块接口设计

1. 项目背景与核心需求解析在嵌入式系统开发中,信号电平的稳定控制是确保设备可靠通信的基础。STM32F446RE作为一款高性能ARM Cortex-M4微控制器,其GPIO模块内置了可编程的上拉/下拉电阻功能,这为与DTH-08这类数字信号处理模块的接口设计提供…

2026/7/13 6:35:41阅读更多 →
STM32与TB6593FNG的直流电机控制方案设计与优化

STM32与TB6593FNG的直流电机控制方案设计与优化

1. 项目背景与核心需求在工业自动化和嵌入式系统开发领域,直流电机控制一直是个经典而重要的课题。最近我在一个自动化分拣设备项目中遇到了一个棘手问题:标准直流电机驱动方案在动态响应和调速精度上无法满足需求。经过多方比较,最终选择了T…

2026/7/13 7:45:50阅读更多 →
TB6593FNG与PIC18F67K40的直流电机控制方案

TB6593FNG与PIC18F67K40的直流电机控制方案

1. 项目背景与核心器件选型在工业自动化和小型机器人领域,直流电机控制一直是基础但关键的技术环节。这次我们要探讨的是基于TB6593FNG全桥驱动芯片和PIC18F67K40微控制器的定制化解决方案——这个组合在中小功率直流电机控制中展现出独特的优势。TB6593FNG是东芝推…

2026/7/13 7:45:50阅读更多 →
英雄联盟Seraphine智能助手:终极免费自动BP与战绩查询工具完全指南

英雄联盟Seraphine智能助手:终极免费自动BP与战绩查询工具完全指南

英雄联盟Seraphine智能助手:终极免费自动BP与战绩查询工具完全指南 【免费下载链接】Seraphine 英雄联盟战绩查询工具 项目地址: https://gitcode.com/gh_mirrors/se/Seraphine 你是否厌倦了在英雄联盟排位赛中手忙脚乱地选择英雄?是否希望在游戏…

2026/7/13 7:45:50阅读更多 →
绝地求生罗技鼠标宏终极指南:5分钟实现无后坐力射击

绝地求生罗技鼠标宏终极指南:5分钟实现无后坐力射击

绝地求生罗技鼠标宏终极指南:5分钟实现无后坐力射击 【免费下载链接】logitech-pubg PUBG no recoil script for Logitech gaming mouse / 绝地求生 罗技 鼠标宏 项目地址: https://gitcode.com/gh_mirrors/lo/logitech-pubg 想要在《绝地求生》中稳定压枪却…

2026/7/13 7:45:50阅读更多 →
TLA2518与PIC18F65K40的工业级ADC接口设计

TLA2518与PIC18F65K40的工业级ADC接口设计

1. TLA2518与PIC18F65K40的硬件架构解析TLA2518作为德州仪器(TI)推出的精密ADC芯片,采用逐次逼近型(SAR)架构,具有8通道多路复用输入能力。这款3mm3mm封装的微型器件在工业传感器接口设计中表现出色,其关键特性包括:12位分辨率下实…

2026/7/13 7:45:50阅读更多 →
ADP5350与PIC18LF45K50构建智能电源管理系统

ADP5350与PIC18LF45K50构建智能电源管理系统

1. 项目背景与核心需求在现代嵌入式系统设计中,电源管理已成为决定产品可靠性和用户体验的关键因素。ADP5350作为ADI公司推出的高性能电源管理IC(PMIC),配合Microchip的PIC18LF45K50低功耗MCU,能够构建一套完整的智能电源管理系统。这种组合特…

2026/7/13 7:40:48阅读更多 →
VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异当你在VSCode中启动一个新的TypeScript项目时,第一个技术决策往往从安装方式开始。这个看似简单的选择——全局安装还是项目本地安装——实际上会深刻影响你的开发流程、团队协作和…

2026/7/13 4:47:19阅读更多 →
智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手 【免费下载链接】zhihuishu 智慧树刷课插件,自动播放下一集、1.5倍速度、无声 项目地址: https://gitcode.com/gh_mirrors/zh/zhihuishu 智慧树刷课插件是一款专为智慧树在线教育平台设计的Chrome浏…

2026/7/13 0:50:34阅读更多 →
Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否在GOG或Epic Games Store购买了心仪的游戏…

2026/7/13 4:52:09阅读更多 →
卡梅德生物技术快报|蛋白质分离纯化:肠激酶可溶性原核表达 + 两步层析全参数|标准化蛋白质分离纯化 SOP

卡梅德生物技术快报|蛋白质分离纯化:肠激酶可溶性原核表达 + 两步层析全参数|标准化蛋白质分离纯化 SOP

研究痛点提出(提出问题)重组肠激酶是融合标签切除核心工具酶,当前原核表达体系存在三大标准化难题,直接阻碍可复现的蛋白质分离纯化流程搭建:Trx、GST、单 SUMO 标签融合产物绝大多数为包涵体,沉淀占比超 9…

2026/7/13 0:04:58阅读更多 →
语音转文字工具AsrTools:让音频整理变得简单高效

语音转文字工具AsrTools:让音频整理变得简单高效

语音转文字工具AsrTools:让音频整理变得简单高效 【免费下载链接】AsrTools ✨ AsrTools: Smart Voice-to-Text Tool | Efficient Batch Processing | User-Friendly Interface | No GPU Required | Supports SRT/TXT Output | Turn your audio into accurate text …

2026/7/13 0:04:58阅读更多 →
Palworld存档编辑完全掌握:从零开始实现游戏数据可视化修改

Palworld存档编辑完全掌握:从零开始实现游戏数据可视化修改

Palworld存档编辑完全掌握:从零开始实现游戏数据可视化修改 【免费下载链接】palworld-save-tools Tools for converting Palworld .sav files to JSON and back 项目地址: https://gitcode.com/gh_mirrors/pa/palworld-save-tools 你是否曾经想要调整Palwor…

2026/7/13 0:04:58阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/13 4:21:17阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/13 4:08:53阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/12 21:43:43阅读更多 →