当前位置: 首页 > news >正文

鸿蒙 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_SELECT=0;// 选择constTOOL_CROP=1;// 裁剪constTOOL_ARROW=2;// 箭头constTOOL_RECT=3;// 矩形constTOOL_TEXT=4;// 文字

数字常量性能更优,配合Record<number, string>快速映射工具名称。


四、关键技术实现

4.1 Canvas 全量重绘策略

renderCanvas()方法每次执行完整的五步流程:

  1. clearRect清空画布
  2. drawImage绘制截图背景(自动缩放至 Canvas 尺寸)
  3. 裁剪模式下绘制覆盖层(暗角遮罩 + 虚线框 + 角标 + 尺寸标注)
  4. 遍历annotations数组绘制所有标注
  5. 拖拽中绘制临时图形

优点:状态一致性极好,不会残留绘图痕迹;实现简单,无需管理脏区域。适合标注数量 < 50 的典型场景。

4.2 箭头绘制的数学原理

箭头头部包含两个翼尖,通过三角函数计算:

constheadLen=Math.max(12,lw*3);constangle=Math.atan2(y2-y1,x2-x1);// 翼尖1: 逆时针30度consthx1=x2-headLen*Math.cos(angle-Math.PI/6);consthy1=y2-headLen*Math.sin(angle-Math.PI/6);// 翼尖2: 顺时针30度consthx2=x2-headLen*Math.cos(angle+Math.PI/6);consthy2=y2-headLen*Math.sin(angle+Math.PI/6);

设计细节headLen = max(12, lw * 3)使箭头大小随线宽自适应——线宽 2 时 headLen 为 12,线宽 8 时 headLen 为 24,视觉效果始终协调。

4.3 裁剪覆盖层的四区域遮罩

裁剪框外部使用四块半透明黑色矩形制造「暗角」效果:

区域起点尺寸
(0, 0)(cw, region.y)
(0, region.y+height)(cw, ch - region.y - height)
(0, region.y)(region.x, height)
(region.x+width, region.y)(cw - region.x - width, height)

搭配蓝色虚线边框 (#0078D4)、四角 8×8 白色手柄方块、以及上方的宽度 × 高度实时尺寸标注,提供了专业级别的裁剪交互体验。

4.4 文字标注的背景垫片设计

文字标注绘制使用「背景垫片」方案:

// 先绘制半透明黑色背景ctx.fillStyle='#80000000';ctx.roundRect(x-pad,y-pad,tw+pad*2,th+pad*2,4);ctx.fill();// 再绘制带颜色的文字ctx.fillStyle=color;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自动缩放显示。裁剪时需通过比例换算还原实际像素坐标:

constscaleX=this.screenshotWidth/this.canvasWidth;constscaleY=this.screenshotHeight/this.canvasHeight;constcropX=Math.round(region.x*scaleX);constcropY=Math.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 状态:

类别变量作用
截图currentScreenshotscreenshotWidth/Height截图图像与尺寸
工具currentToolselectedColor/LW/FS当前工具和样式
标注annotations标注列表
裁剪cropRegionisCropped裁剪区域与状态
延时delayIndexcountdownisCapturing倒计时与截图状态
交互showTextInputtextInputValue文字输入弹窗
CanvascanvasWidth/Height画布尺寸
反馈statusText状态栏信息

@State变量的任何变更都会自动触发 UI 重渲染,使得标注增删操作简洁高效:

// 添加标注 — 展开新数组触发响应式更新this.annotations=[...this.annotations,ann];// 撤销标注 — Array.slice 创建新数组this.annotations=this.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.json"pages/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 上实现了完整的截图标注工作流。项目的核心亮点:

  1. 一体化体验:截图 → 标注 → 保存/分享,全部在一个界面完成。
  2. 专业标注引擎:箭头 30° 翼尖角度、矩形半透明填充、文字背景垫片,均达到专业水准。
  3. 精细交互反馈:裁剪暗角遮罩、实时尺寸标注、倒计时动画、状态栏同步更新。
  4. 可靠错误处理:try/catch 异常捕获、二次确认弹窗、按钮禁用状态管理。

从路由配置到权限声明,从 Canvas 绘图到文件编码保存,本项目完整展示了 HarmonyOS NEXT 上 PC 端工具类应用的开发全流程。

后续可扩展方向

  • 接入@ohos.multimedia.screenshot真实截图 API
  • 马赛克/模糊标注(隐私保护)
  • 截图历史记录管理
  • OCR 文字识别
  • 云存储一键上传

本文由 AtomCode AI 助手生成,完整源码位于entry/src/main/ets/pages/ScreenshotTool.ets

http://www.rkmt.cn/news/1489570.html

相关文章:

  • DayZ社区离线模式完整指南:打造你的专属单人末日世界
  • Ki67抗体如何解码细胞增殖与肿瘤预后?
  • nvpro_core2 详解:NVIDIA Vulkan / OpenGL 图形样例背后的现代 C++ 基础库
  • 【RT-DETR实战】170、遥感目标检测综合项目:UCAS-AOD数据集实战
  • 计算机毕业设计之django基于Hadoop的运动员健康分析系统的设计与实现
  • OpenCV导向滤波(Guided Filter)参数eps和d怎么调?看完这篇实战避坑指南就懂了
  • 2026年Q2成都木方租赁可靠服务商技术选型参考:工地木方租赁电话/成都建筑模板木方/成都旧木方回收电话/成都木方回收哪家好/选择指南 - 优质品牌商家
  • 2026阳江GEO优化公司TOP5权威排名发布,融景科技登顶行业榜首 - 广东科技观察
  • 2026阳江GEO优化哪家靠谱?AI收录优选服务商深度解析 - 广东科技观察
  • 智慧工地无人机航拍检测 | 建筑物料智能盘点 施工设备监测 深度学习目标检测数据集实战
  • Zotero-GPT插件API集成故障排查:5种常见问题深度解析与解决方案
  • 2026苏州通风设备定制厂家选择指南 - 品牌排行榜
  • 会计引擎原理及流程 - 智慧园区
  • 如何快速安装和使用网盘直链下载助手:九大网盘免费高速下载完整指南
  • 2026年6月值得信赖的诸城行星夹层锅公司哪家*榜,电加热/蒸汽/燃气行星夹层锅制造厂家选择指南 - 海棠依旧大
  • 2026氮气烘箱厂家解析及行业应用指南 - 品牌排行榜
  • 海参崴旅游服务机构客观排行:维度对比与适配参考 - 互联网科技品牌测评
  • 如何用pyVideoTrans实现视频多语言翻译配音:开源神器完整指南
  • Uncle小说PC版:一站式免费开源小说阅读下载终极方案
  • 2026洁净烘箱厂家推荐及行业应用解析 - 品牌排行榜
  • 闽南姜母鸭品牌排行实测:厦门网红打卡小吃、闽南姜母鸭、黄厝网红打卡小吃、厦门伴手礼、厦门姜母鸭伴手礼、厦门姜母鸭小吃选择指南 - 优质品牌商家
  • 2026行业实力评估:金属探测安检门生产厂家汇总,深度分析品意安检手机探测门、探铜门及工厂专用安检门厂家 - 栗子测评
  • 2026商业展示道具厂家技术选型与成本控制指南:金属展示架生产厂家、陈列道具生产厂家、专卖店展示柜生产厂家、办公家具定制公司选择指南 - 优质品牌商家
  • 主流指纹浏览器:AdsPower/Multilogin/GoLogin架构剖析
  • 2026 摄影师修图软件推荐|商业摄影后期工具像素蛋糕深度测评
  • 精通幻兽帕鲁存档编辑:专业级游戏数据转换实战指南
  • 第4篇:《面试题:推挽输出和开漏输出有什么区别?为什么两个推挽接一起会烧IO?》
  • 榆次聚餐宴请指南:悦宴以酥皮烤鸭与家常粤味服务本地食客圈层
  • 从‘显示所有’到‘按需展示’:FineReport动态列隐藏技巧与INARRAY函数实战解析
  • 高速PCB,六层板电路板最合适的结构