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

实现多路标注截图

1. 准备截图环境

  • 创建合成画布:新建一个与原始参考尺寸(referenceWidthreferenceHeight)一致的临时画布,用于合成背景、视频内容和标注信息。
  • 获取有效视频元素:筛选页面中已加载的视频元素(readyState >= 2且尺寸有效),确保截图包含实时视频内容。

2. 绘制基础内容

  • 填充背景:在合成画布上用白色填充整个区域,作为截图的基础背景。
  • 绘制视频内容
    • 计算视频元素在标注容器中的相对位置和尺寸。
    • 根据相对比例将视频绘制到合成画布的对应位置,保证视频内容与标注的空间对应关系。

3. 绘制标注信息

  • 遍历标注历史:将drawingHistory中存储的所有标注动作(包括手绘、图形、文字、马赛克等)绘制到合成画布。
  • 处理当前绘制内容:如果存在正在绘制但未完成的动作(currentAction),同样将其绘制到画布,确保截图完整性。
  • 按工具类型绘制:针对不同标注工具(如马赛克、箭头、文字等),调用对应的绘制方法,将百分比坐标转换为合成画布的实际像素坐标后绘制。

4. 导出与下载截图

  • 生成图片数据:通过canvas.toDataURL('image/png')将合成画布内容转换为 PNG 格式的图片数据 URL。
  • 触发下载
    • 创建临时<a>标签,设置download属性指定文件名(含时间戳确保唯一性)。
    • 将图片数据 URL 赋值给<a>标签的href属性,模拟点击实现下载。
    • 清理临时元素和 URL,释放内存。

5. 异常处理与反馈

  • 错误捕获:使用try-catch捕获截图过程中的异常(如 canvas 操作失败),并通过ElMessage提示用户。
  • 成功反馈:截图成功后,通过ElMessage显示成功提示,提升用户体验。

步骤 1:触发截图功能

用户点击 “截图” 按钮时,调用takeScreenshot方法启动截图流程。

对应代码

步骤 2:获取有效视频元素

筛选页面中已加载的视频元素(排除未就绪或无尺寸的视频),确保截图包含实时视频内容。

对应代码

步骤 3:创建合成画布

新建与原始参考尺寸(referenceWidthreferenceHeight)一致的临时画布,用于合成背景、视频和标注。

对应代码

步骤 4:绘制基础背景

在合成画布上填充白色背景,作为截图的底层。

对应代码

步骤 5:绘制视频内容

计算视频在标注容器中的相对位置,按比例绘制到合成画布,确保视频与标注位置对应。

对应代码

步骤 6:绘制标注内容

将历史标注和当前正在绘制的内容(如手绘、图形、马赛克等)绘制到合成画布。

对应代码

// 绘制历史标注
drawingHistory.value.forEach(action => {drawActionToCanvas(action, ctx, compositeCanvas);
});
// 绘制当前正在绘制的内容(未完成的标注)
if (currentAction) {drawActionToCanvas(currentAction, ctx, compositeCanvas);
}// 绘制单个标注到合成画布的方法
const drawActionToCanvas = (action: DrawingAction, ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement) => {const { tool, points, color, width, text } = action;// 将百分比坐标转换为合成画布的实际像素坐标const actualPoints = points.map(p => ({x: p.x * canvas.width,y: p.y * canvas.height}));// 设置绘图样式ctx.strokeStyle = color;ctx.fillStyle = color;ctx.lineWidth = width;// 根据工具类型绘制不同内容(以马赛克为例)switch (tool) {case 'mosaic':if (actualPoints.length) {drawMosaicToCanvas(actualPoints[0], width, ctx, canvas);}break;// 其他工具(pen/line/rectangle等)的绘制逻辑类似,调用对应方法// ...}
};// 马赛克在截图中的绘制方法
const drawMosaicToCanvas = (position: Point,size: number,ctx: CanvasRenderingContext2D,canvas: HTMLCanvasElement
) => {// 创建临时画布绘制马赛克图案const tempCanvas = document.createElement('canvas');tempCanvas.width = size;tempCanvas.height = size;const tempCtx = tempCanvas.getContext('2d');if (!tempCtx) return;// 绘制马赛克块(固定颜色#50B19D)tempCtx.fillStyle = '#50B19D';tempCtx.strokeStyle = 'rgba(255, 255, 255, 0.2)'; // 块间边框const cellSize = 10; // 马赛克块大小for (let y = 0; y < size; y += cellSize) {for (let x = 0; x < size; x += cellSize) {tempCtx.fillRect(x, y, cellSize, cellSize); // 填充块tempCtx.strokeRect(x, y, cellSize, cellSize); // 块边框}}// 绘制马赛克外边框和角落标记(增强可视性)tempCtx.strokeStyle = 'rgba(80, 177, 157, 0.8)';tempCtx.lineWidth = 2;tempCtx.strokeRect(0, 0, size, size); // 外边框const cornerSize = 8;tempCtx.fillRect(0, 0, cornerSize, cornerSize); // 左上角标记tempCtx.fillRect(size - cornerSize, 0, cornerSize, cornerSize); // 右上角标记tempCtx.fillRect(0, size - cornerSize, cornerSize, cornerSize); // 左下角标记tempCtx.fillRect(size - cornerSize, size - cornerSize, cornerSize, cornerSize); // 右下角标记// 将马赛克绘制到合成画布ctx.drawImage(tempCanvas, position.x - size / 2, position.y - size / 2, size, size);
};

 

步骤 7:导出并下载截图

将合成画布内容转换为图片 URL,通过临时链接触发下载,并清理资源。

总结

截图功能通过创建合成画布分层绘制(背景→视频→标注)导出下载的流程,实现了标注内容与原始画面的精准融合,同时保留了马赛克等隐私保护元素。核心是通过坐标比例转换确保各元素位置对齐,以及临时画布技术处理复杂标注(如马赛克)的绘制。

 

http://www.lryc.cn/news/603419.html

相关文章:

  • WMS仓储管理系统在不良品管理中的优化策略
  • OpenCL - study - code04 canny
  • C++基础:模拟实现priority_queue(堆),详细介绍仿函数
  • Python 程序设计讲义(29):字符串的处理方法——大小写转换
  • 网络数据传输与NAT技术的工作原理
  • 计算机网络五层模型
  • 【微信小程序】12、生物认证能力
  • .gitignore 添加 vue.config.js 时不好使
  • 微信小程序无法构建npm,可能是如下几个原因
  • Excel批量加密工具,一键保护多个文件
  • 聚观早报 | 三星获特斯拉AI芯片订单;小米16首发成安卓最强SOC;iPhone 17 Pro支持8倍光学变焦
  • 递归推理树(RR-Tree)系统:构建认知推理的骨架结构
  • [leetcode] 实现 Trie (前缀树)
  • 开发避坑短篇(8):Java Cookie值非法字符异常分析与解决方案:IllegalArgumentException[32]
  • 【C#获取高精度时间】
  • 智能落地扇方案:青稞RISC-V电机 MCU一览
  • SZU大学物理实验报告|电位差计
  • 【dropdown组件填坑指南】—怎么实现下拉框的位置计算
  • python cli命令 cli工具命令 自定义cli命名 开发 兼容 window、mac、linux,调用示例
  • React面试题目和答案大全
  • 注册发送手机短信
  • Linux 完整删除 Systemd 服务的步骤
  • 【自制组件库】从零到一实现属于自己的 Vue3 组件库!!!
  • Rust 实战三 | HTTP 服务开发及 Web 框架推荐
  • leaflet中绘制轨迹线的大量轨迹点,解决大量 marker 绑定 tooltip 同时显示导致的性能问题
  • HTTP 与 HTTPS 的区别
  • div 封装日历
  • C++学习之继承
  • scrapy框架新浪新闻
  • linux中简易云盘系统项目实战:基于 TCP协议的 Socket 通信、json数据交换、MD5文件区别与多用户文件管理实现