鸿蒙 PC 端截图标注工具全解析
鸿蒙 PC 端截图标注工具全解析技术栈: HarmonyOS NEXT (API 23) · ArkTS · Canvas · PixelMap代码行数: ~1330 行适用设备: PC / 平板支持鼠标交互一、背景与设计目标PC 端日常办公中截图工具是最高频的生产力需求之一。撰写文档、制作教程、记录 Bug、协作沟通——几乎每天都需要截图 标注。然而 HarmonyOS NEXT 系统的原生截图通常仅提供基础截取能力缺少标注增强。本项目基于 HarmonyOS NEXT API 23用 ArkTS 语言实现了一款全功能 PC 端截图标注工具支持截图 → 标注 → 裁剪 → 保存/分享的一站式工作流。整个工具共有约 1330 行 Kotlin-ETS 代码包含了完整的 UI 交互、Canvas 绘图引擎和图像编解码处理。二、整体架构2.1 文件组成文件作用ScreenshotTool.ets主组件含 UI、绘图、业务逻辑 (~1330 行)main_pages.json注册pages/ScreenshotTool路由module.json5声明ohos.permission.CAPTURE_SCREEN权限string.json添加capture_screen_reason权限说明字符串2.2 模块划分┌──────────────────────────────────────────────┐ │ ScreenshotTool │ ├──────────────────────────────────────────────┤ │ ① 常量定义 (工具模式 / 颜色 / 线宽 / 延时) │ │ ② 类型接口 (Annotation / CropRegion / Point) │ │ ③ 绘图工具函数 (箭头/矩形/文字/裁剪覆盖层) │ │ ④ 主组件 (18个状态变量 / 截图 / 标注 / 裁剪) │ │ ⑤ UI 构建 (8 个 Builder 子组件) │ └──────────────────────────────────────────────┘三、核心数据结构3.1 标注数据模型interfaceAnnotation{type:arrow|rectangle|text;startX:number;startY:number;endX:number;endY:number;color:string;lineWidth:number;text:string;fontSize:number;}使用联合类型type区分标注形态渲染时根据类型选择对应的绘图函数。3.2 裁剪区域模型interfaceCropRegion{x:number;y:number;width:number;height:number;}裁剪区域在鼠标拖拽中动态计算每次更新触发 Canvas 全量重绘实现所见即所得的预览。3.3 工具模式枚举constTOOL_SELECT0;// 选择constTOOL_CROP1;// 裁剪constTOOL_ARROW2;// 箭头constTOOL_RECT3;// 矩形constTOOL_TEXT4;// 文字数字常量性能更优配合Recordnumber, string快速映射工具名称。四、关键技术实现4.1 Canvas 全量重绘策略renderCanvas()方法每次执行完整的五步流程clearRect清空画布drawImage绘制截图背景自动缩放至 Canvas 尺寸裁剪模式下绘制覆盖层暗角遮罩 虚线框 角标 尺寸标注遍历annotations数组绘制所有标注拖拽中绘制临时图形优点状态一致性极好不会残留绘图痕迹实现简单无需管理脏区域。适合标注数量 50 的典型场景。4.2 箭头绘制的数学原理箭头头部包含两个翼尖通过三角函数计算constheadLenMath.max(12,lw*3);constangleMath.atan2(y2-y1,x2-x1);// 翼尖1: 逆时针30度consthx1x2-headLen*Math.cos(angle-Math.PI/6);consthy1y2-headLen*Math.sin(angle-Math.PI/6);// 翼尖2: 顺时针30度consthx2x2-headLen*Math.cos(angleMath.PI/6);consthy2y2-headLen*Math.sin(angleMath.PI/6);设计细节headLen max(12, lw * 3)使箭头大小随线宽自适应——线宽 2 时 headLen 为 12线宽 8 时 headLen 为 24视觉效果始终协调。4.3 裁剪覆盖层的四区域遮罩裁剪框外部使用四块半透明黑色矩形制造「暗角」效果区域起点尺寸上(0, 0)(cw, region.y)下(0, region.yheight)(cw, ch - region.y - height)左(0, region.y)(region.x, height)右(region.xwidth, region.y)(cw - region.x - width, height)搭配蓝色虚线边框 (#0078D4)、四角 8×8 白色手柄方块、以及上方的宽度 × 高度实时尺寸标注提供了专业级别的裁剪交互体验。4.4 文字标注的背景垫片设计文字标注绘制使用「背景垫片」方案// 先绘制半透明黑色背景ctx.fillStyle#80000000;ctx.roundRect(x-pad,y-pad,twpad*2,thpad*2,4);ctx.fill();// 再绘制带颜色的文字ctx.fillStylecolor;ctx.fillText(text,x,y);这确保了文字在任何颜色的截图背景上都清晰可辨。4.5 延时截图与倒计时提供 6 个延时档位即时 / 3s / 5s / 10s / 15s / 30s。核心逻辑在captureScreen()中通过for循环 await this.sleep(1000)实现逐秒倒计时。UI 层同步展示标题栏右侧LoadingProgress 数字倒计时截图按钮在倒计时期间禁用状态栏文字更新提示4.6 截图尺寸适配Canvas 默认尺寸为 800×500截图通过drawImage自动缩放显示。裁剪时需通过比例换算还原实际像素坐标constscaleXthis.screenshotWidth/this.canvasWidth;constscaleYthis.screenshotHeight/this.canvasHeight;constcropXMath.round(region.x*scaleX);constcropYMath.round(region.y*scaleY);4.7 图像编码与保存流程PixelMap → ImagePacker.packing() → ArrayBuffer → fileIo.openSync(CREATE|WRITE_ONLY) → fileIo.writeSync() → 磁盘文件使用 PNG 无损格式 quality: 100文件名使用时间戳保证唯一性。保存成功后弹出对话框提供「好的」和「分享」两个选项。五、UI 构建与交互设计5.1 界面布局纵向 Column┌──────────────────────────────────────┐ │ 截图工具 PC 端截图与标注工具 │ ← 标题栏 │ ⏱ [即时|3s|5s|…] [截取][重截] │ ← 截图控制栏 │ ┌──────────────────────────────────┐ │ │ │ Canvas 截图 标注显示区域 │ │ ← 画布区域 (核心) │ └──────────────────────────────────┘ │ │ [✂️应用裁剪] [取消裁剪] │ ← 裁剪操作按钮 │ [选择][裁剪]│[箭头][矩形][文字]│[撤]…│ ← 工具栏 │ 颜色 ●●●● │ 线宽 ▬▬ │ 字号│ ← 样式选择栏 │ 状态文字... 1920×1080 │ ← 状态栏 └──────────────────────────────────────┘5.2 响应式状态管理工具使用 18 个State变量管理所有 UI 状态类别变量作用截图currentScreenshot、screenshotWidth/Height截图图像与尺寸工具currentTool、selectedColor/LW/FS当前工具和样式标注annotations标注列表裁剪cropRegion、isCropped裁剪区域与状态延时delayIndex、countdown、isCapturing倒计时与截图状态交互showTextInput、textInputValue文字输入弹窗CanvascanvasWidth/Height画布尺寸反馈statusText状态栏信息State变量的任何变更都会自动触发 UI 重渲染使得标注增删操作简洁高效// 添加标注 — 展开新数组触发响应式更新this.annotations[...this.annotations,ann];// 撤销标注 — Array.slice 创建新数组this.annotationsthis.annotations.slice(0,-1);5.3 三阶段鼠标事件处理PC 端交互通过 Canvas 的onMouse事件实现阶段动作处理逻辑Press按下记录起始坐标进入绘图/裁剪状态Move移动实时更新坐标调用renderCanvas()渲染预览Release松开判断有效性距离 5px 则加入标注列表特殊处理裁剪模式的 Move 事件更新cropRegion变量而非绘制临时图形文字模式的 Press 事件直接弹出输入框不进入拖拽状态5.4 抽象的 Builder 组件BuildertoolButton(label,toolType)// 自动响应选中状态BuildertoolDivider()// 竖向分隔线BuilderactionButton(label,color,bg,action)// 通用操作按钮toolButton根据currentTool自动切换样式选中态显示蓝色背景边框未选中态为灰色背景。六、边界处理与容错6.1 空状态引导无截图时 Canvas 区域显示 图标 引导文字「点击上方截取屏幕按钮」和功能介绍。6.2 二次确认保护不可逆操作重新截图、清空标注使用AlertDialog弹窗确认防止误操作。6.3 裁剪边界校验裁剪区域 10×10px 时弹出 Toast 提示「裁剪区域太小」并拒绝执行。6.4 异常捕获所有异步操作截图、裁剪、保存均被try/catch包裹console.error输出详细日志promptAction.showToast显示友好提示statusText更新错误状态文字6.5 按钮禁用逻辑截图按钮: enabled{!this.isCapturing this.countdown 0} 重新截图: enabled{this.currentScreenshot ! null}截图进行中或倒计时进行中截图按钮自动禁用防止重复触发。七、部署配置配置项文件内容路由注册main_pages.jsonpages/ScreenshotTool权限声明module.json5ohos.permission.CAPTURE_SCREEN权限理由string.json「用于截取屏幕内容并进行标注编辑」启动页EntryAbility.etsloadContent(pages/ScreenshotTool)八、性能特征操作复杂度说明渲染截图O(1)drawImage GPU 加速渲染标注O(n)n 标注数量裁剪预览O(1)4 次 fillRect 1 次 strokeRect保存编码O(w×h)全像素编码大图时较耗时优化方向标注数量 100 时可改用双 Canvas 分离截图背景层和标注层4K 分辨率保存时添加进度指示裁剪拖拽中使用缩略图预览提升流畅度九、总结本工具使用纯 ArkTS 在 HarmonyOS NEXT 上实现了完整的截图标注工作流。项目的核心亮点一体化体验截图 → 标注 → 保存/分享全部在一个界面完成。专业标注引擎箭头 30° 翼尖角度、矩形半透明填充、文字背景垫片均达到专业水准。精细交互反馈裁剪暗角遮罩、实时尺寸标注、倒计时动画、状态栏同步更新。可靠错误处理try/catch 异常捕获、二次确认弹窗、按钮禁用状态管理。从路由配置到权限声明从 Canvas 绘图到文件编码保存本项目完整展示了 HarmonyOS NEXT 上 PC 端工具类应用的开发全流程。后续可扩展方向接入ohos.multimedia.screenshot真实截图 API马赛克/模糊标注隐私保护截图历史记录管理OCR 文字识别云存储一键上传本文由 AtomCode AI 助手生成完整源码位于entry/src/main/ets/pages/ScreenshotTool.ets。