【Vue】vue3 在图片上渲染 OCR 识别后的文本框、可复制文本组件
需求
- 后面返回解析后的文本和四角坐标,在图片上渲染成框,并且可复制。
- 图片还可以缩放、拖拽


实现
这里要重点讲下关于OCR文本框的处理:
因为一些文字可能是斜着放的,所有我们要特殊处理,根据三角函数来计算出它的偏转角度,从而旋转,所有下面的 handleStyle 函数有点复杂,不说明怕你看不懂😂
<template><div class="preview-wrap" @mousewheel="handerMousewheel"><div class="preview"><divclass="preview-content":style="{top: imgConfig.imgTop + 'px',left: imgConfig.imgLeft + 'px',transform: `scale(${imgConfig.imgScale}) rotateZ(${imgConfig.imgRotate}deg)`,}"ref="previewContentRefs"@mousedown="handleMoveStart"><img :src="src" @load="onImageLoaded($event)" /><!-- OCR 识别框 --><template v-if="imgConfig.width && imgConfig.height && ocrInfo?.length"><divclass="ocr-box"v-for="item in ocrInfo":style="handleStyle(item[2])">{{ item[0] }}</div></template></div></div></div>
</template><script setup lang="ts">
import { reactive, ref } from 'vue';
interface Props {src: string;ocrInfo?: OCRInfoItem[];
}
const props = defineProps<Props>();
const imgConfig = reactive({width: 0, // 图片原始宽度height: 0, // 图片原始高度wrapWidth: 0, // 图片容器宽度wrapHeight: 0, // 图片容器高度startPageX: 0, // 按下鼠标时当前鼠标所在位置xstartPageY: 0, // 按下鼠标时当前鼠标所在位置yimgTop: 0, // 图片定位置topimgLeft: 0, // 图片定位置leftimgScale: 1, // 图片缩放imgRotate: 0, // 图片旋转
});
const previewContentRefs = ref<HTMLElement | null>(null);const handleStyle = (axis: any) => {
// 这里为什么要处理三角形:因为一些文字是偏转的,需要特殊处理角度。// 处理偏斜的文字// 三角形的高const triangleY = axis[0][1] - axis[1][1];// 三角形的底const triangleX = axis[1][0] - axis[0][0];// 三角形的斜边const triangle = Math.sqrt(Math.abs(triangleY * triangleY) + Math.abs(triangleX * triangleX),);// sinA = 对边 / 斜边const sinA = triangleY / triangle;// 旋转角度 = asin(sinA) / π * 180let rotate = Math.asin(sinA) / (Math.PI / 180);return {width: ((axis[1][0] - axis[0][0]) / imgConfig.width) * 100 + '%',height: ((axis[3][1] - axis[0][1]) / imgConfig.height) * 100 + '%',top: (axis[0][1] / imgConfig.height) * 100 + '%',left: (axis[0][0] / imgConfig.width) * 100 + '%',fontSize:((axis[3][1] - axis[0][1]) / imgConfig.height) * imgConfig.wrapHeight +'px',// 注意旋转正负 三角形的高大于0 旋转角度为负数transform: `rotate(${triangleY > 0 ? '-' : ''}${rotate}deg)`,};
};// 鼠标滚轮缩放图片
const handerMousewheel = (e: any) => {// 鼠标没有在图片区域内就不缩放(解决多列表下拉问题)if (e.target.className !== 'preview') {// 火狐浏览器为e.detail 其他浏览器均为e.wheelDeltaif ((e.wheelDelta > 0 || e.detail > 0) && imgConfig.imgScale < 4) {imgConfig.imgScale += 0.1;} else if ((e.wheelDelta < 0 || e.detail < 0) && imgConfig.imgScale > 0.5) {imgConfig.imgScale += -0.1;}// 阻止浏览器默认滚动事件e.preventDefault();}
};const onImageLoaded = (event: any) => {if (previewContentRefs.value) {// 图片加载完成后获取图片容器的宽高imgConfig.wrapWidth = previewContentRefs.value.clientWidth;imgConfig.wrapHeight = previewContentRefs.value.clientHeight;}// 获取图片的原始宽高const { naturalWidth, naturalHeight } = event.target;imgConfig.width = naturalWidth;imgConfig.height = naturalHeight;
};// 按下鼠标开始移动图片
const handleMoveStart = (e: any) => {// 如果不是图片就不拖动if (e.target.tagName !== 'IMG') {return;}const { pageX, pageY } = e;imgConfig.startPageX = pageX - imgConfig.imgLeft;imgConfig.startPageY = pageY - imgConfig.imgTop;document.addEventListener('mousemove', handleMore, false);document.addEventListener('mouseup', clearEvent, false);e.preventDefault();
};// 移除事件
const clearEvent = () => {document.removeEventListener('mousemove', handleMore, false);
};// 按住鼠标移动时的处理
const handleMore = (e: any) => {const { pageX, pageY } = e;imgConfig.imgTop = pageY - imgConfig.startPageY;imgConfig.imgLeft = pageX - imgConfig.startPageX;e.preventDefault();
};
</script><style scoped lang="scss">
.preview-wrap {width: 100%;height: 100%;overflow: hidden;li {list-style: none;}.preview {position: relative;display: flex;align-items: center;justify-content: center;width: 100%;height: 100%;&-content {position: relative;transition: 0.2s transform;height: 100%;> img {width: auto;height: 100%;// 禁止图片拖动-webkit-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;// 禁止拖拽-webkit-user-drag: none;-moz-user-drag: none;-ms-user-drag: none;}.ocr-box {position: absolute;left: 0;top: 0;background-color: rgba(255, 240, 108, 0.3);color: transparent;box-sizing: border-box;overflow: hidden;line-height: 1;text-align: justify; // 两端对齐text-align-last: justify; // 两端对齐&::selection {background-color: rgba(49, 140, 238, 0.5);}}}&-footer {position: absolute;bottom: 20px;left: 50%;transform: translateX(-50%);&-tools {display: flex;justify-content: center;li {margin-right: 10px;padding: 10px;border-radius: 50%;background: rgba(110, 110, 110, 0.7);cursor: pointer;> img {display: block;width: 30px;height: 30px;}&:hover {i {color: #ef544e;}}}}&-thumbs {margin-top: 20px;max-width: 700px;overflow-x: auto;white-space: nowrap;.thumb-item {padding: 10px;margin-right: 10px;display: inline-block;background: rgba(102, 102, 102, 0.7);border-radius: 5px;cursor: pointer;img {width: 60px;height: 60px;object-fit: cover;}&.active {background: rgba(239, 84, 78, 0.7);}}&::-webkit-scrollbar {height: 10px;}&::-webkit-scrollbar-thumb {border-radius: 10px;-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);background: #d2d2d2;cursor: pointer;}&::-webkit-scrollbar-track {border-radius: 10px;background: #fff;}}}.close-icon {padding: 10px;position: absolute;top: 30px;right: 30px;border-radius: 50%;background: rgba(110, 110, 110, 0.7);cursor: pointer;> img {display: block;width: 30px;height: 30px;}}}
}
</style>相关文章:
【Vue】vue3 在图片上渲染 OCR 识别后的文本框、可复制文本组件
需求 后面返回解析后的文本和四角坐标,在图片上渲染成框,并且可复制。图片还可以缩放、拖拽 实现 这里要重点讲下关于OCR文本框的处理: 因为一些文字可能是斜着放的,所有我们要特殊处理,根据三角函数来计算出它的偏…...
Linux系统运维脚本:批量创建linux用户和密码(读取文件中的账号和密码来批量创建用户)
目 录 一、要求 二、解决方案 (一)解决思路 (二)方案 三、脚本程序实现 (一)脚本代码和解释 1、脚本代码 2、代码解释 (二)脚本验证 1、脚本编辑 2、给予执行权…...
重力坝廊道量水堰计与堰板安装技术指南
在水利工程中,重力坝廊道量水堰计的安装是确保水资源有效监测与管理的关键环节。本文将详细阐述量水堰计及量水堰板的安装方法,以确保安装质量,提高水资源利用效率。 一、量水堰计的安装位置 量水堰计应安装在堰板的上游,距离堰板…...
ButterKnife实现之Android注解处理器使用教程
ButterKnife实现之Android注解处理器使用教程 1、新建一个注解 1.1、编译时注解 创建注解所需的元注解Retention包含3个不同的值,RetentionPolicy.SOURCE、RetentionPolicy.CLASS、RetentionPolicy.RUNTIME。这3个值代表注解不同的保留策略。 使用RetentionPolic…...
【哈希】Leetcode 128. 最长连续序列 【中等】
最长连续序列 给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。请你设计并实现时间复杂度为 O(n) 的算法解决此问题。示例 1:输入:nums [100,4,200,1,3,2]输出&#x…...
回溯是怎么回事(算法村第十八关青铜挑战)
组合 77. 组合 - 力扣(LeetCode) 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1: 输入:n 4, k 2 输出: [[2,4],[3,4],[2,3],[1,2],[1,3],…...
向爬虫而生---Redis 探究篇5<Redis集群刨根问底(1)>
前言: Redis集群是一种可靠和高性能的分布式数据库解决方案。随着互联网的迅速发展和数据规模的增长,传统的单机Redis已经无法满足大规模应用的需求。Redis集群的出现填补了这一空白,提供了更高的可扩展性和容错性。 大家都知道,Redis是一种基于内存的高性能键值存储数据库,…...
系统集成Prometheus+Grafana
根据产品需求在自己的系统中添加一个系统监控的页面,其中有主机信息的显示,也有一些业务信息的显示。调研后的方案是 主机信息通过Prometheus采集和存储,业务信息通过自己系统的调度任务统计后存储在Mysql中,使用Grafana对接Prome…...
实例驱动计算机网络
文章目录 计算机网络的层次结构应用层DNSHTTP协议HTTP请求响应过程 运输层TCP协议TCP协议面向连接实现TCP的三次握手连接TCP的四次挥手断开连接 TCP协议可靠性实现TCP的流量控制TCP的拥塞控制TCP的重传机制 UDP协议 网际层IP协议(主机与主机)IP地址的分类…...
Unity 报错:SSL CA certificate error
使用UnityWebRequest时出现如下报错: SSL CA certificate error Curl error 60: Cert verify failed: UNITYTLS_X509VERIFY_FLAG_USER_ERROR1 原因: 证书验证失败 和 SSL CA证书错误 解决方法: 创建一个如下的类: /// <…...
算法刷题Day1 | 704.二分查找、27.移除元素
目录 0 引言1 二分查找1.1 我的解题1.2 修改后1.3 总结 2 移除元素2.1 暴力求解2.2 双指针法(快慢指针) 🙋♂️ 作者:海码007📜 专栏:算法专栏💥 标题:代码随想录算法训练营第一天…...
大数据技术学习笔记(五)—— MapReduce(2)
目录 1 MapReduce 的数据流1.1 数据流走向1.2 InputFormat 数据输入1.2.1 FileInputFormat 切片源码、机制1.2.2 TextInputFormat 读数据源码、机制1.2.3 CombineTextInputFormat 切片机制 1.3 OutputFormat 数据输出1.3.1 OutputFormat 实现类1.3.2 自定义 OutputFormat 2 Map…...
北斗导航 | 同步双星故障的BDS/GPS接收机自主完好性监测算法
===================================================== github:https://github.com/MichaelBeechan CSDN:https://blog.csdn.net/u011344545 ===================================================== 同步双星故障的BDS/GPS接收机自主完好性监测算法 1 引言2 同步双星故障…...
2024金三银四必看前端面试题!简答版精品!
文章目录 导文面试题 导文 2024金三银四必看前端面试题!2w字精品!简答版 金三银四黄金期来了 想要跳槽的小伙伴快来看啊 面试题 基于您给出的方向,我将为您生成20个面试题和答案。请注意,由于面试题的答案可能因个人经验和理解而…...
Python-sklearn.datasets-make_blobs
sklearn.datasets.make_blobs()函数形参详解 """ Title: datasets for regression Time: 2024/3/5 Author: Michael Jie """from sklearn import datasets import matplotlib.pyplot as plt# 产生服从正态分布的聚类数据 x, y, cen…...
[最佳实践] conda环境内安装cuda 和 Mamba的安装
Mamba安装失败的过程中,causal-conv1d安装报错为连接超时 key word: vision mamba, DL ,深度学习 ,mamba unet,mamba环境安装 Mamba安装 主要故障是 pip install causal-conv1d1.2.0和 pip install mamba-ssm1.2.0 安…...
【算法】顺时针打印矩阵(图文详解,代码详细注释
目录 题目 代码如下: 题目 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。例如:如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则打印出数字:1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10 这一道题乍一看,没有包含任何复杂的数据结构和…...
蚂蚁感冒c++
题目 思路 “两蚂蚁碰面会掉头,若其中一只蚂蚁感冒了,会把感冒传染给碰到的蚂蚁”,这句话看作是“两蚂蚁碰面会互相穿过,只是把感冒的状态传给了另一只蚂蚁”,因为哪只蚂蚁感冒了并不是题目的重点,重点是有…...
python Plotly可视化
文章目录 Plotly常用函数PolarPlotlymake_subplotsadd_tracego.Scatterpolarglupdate_tracesupdate_layout综合示例 完整版 Python在数据可视化方面有着丰富的库和函数,其中一些常用的库包括 Matplotlib、Seaborn、Plotly、Bokeh等。 Plotly是一个交互式绘图库&…...
刷题第10天
代码随想录刷题第10天 |● 239. 滑动窗口最大值 ● 347.前 K 个高频元素 239. 滑动窗口最大值 唉,好难,先记个思路吧 class Solution { private:class MyQueue { //单调队列(从大到小)public:deque<int> que; // 使用deq…...
SPICE仿真实战:从时序分析基础到建立保持时间验证
1. 项目概述:从“香料”到“时序”的工程思维“时序分析基本概念介绍”这个标题,乍一看可能有点割裂。前半部分“时序分析基本概念介绍”指向一个非常经典且基础的电子工程领域——信号在时间维度上的行为分析,这是电路设计、通信系统乃至嵌入…...
别再死记硬背了!用NestJS + TypeORM实战‘用户-标签’系统,搞懂OneToMany和ManyToOne
NestJS TypeORM实战:构建高可维护的用户标签系统 在开发内容管理平台时,用户与标签的关联关系是典型的多对一建模场景。本文将带你从零实现一个基于NestJS和TypeORM的生产级用户标签系统,重点解析OneToMany和ManyToOne在实际项目中的最佳实践…...
如何为多个并行项目设置Taotoken Token Plan以优化成本
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 如何为多个并行项目设置Taotoken Token Plan以优化成本 应用场景类,同时进行多个AI应用实验或开发的个人或团队&#x…...
保姆级教程:在Ubuntu上把YOLOv5的ONNX模型转成RV1126能用的RKNN模型(附完整代码)
从ONNX到RKNN:YOLOv5模型在RV1126平台的完整转换指南 当清晨的第一缕阳光透过窗帘缝隙洒在键盘上,我正盯着终端里那个顽固的ONNX模型发愁——它已经在我的Ubuntu工作站上运行了整整一夜,却依然没能成功转换为RV1126开发板可用的RKNN格式。这…...
机器人学习快速入门指南:掌握Open X-Embodiment开源数据集
机器人学习快速入门指南:掌握Open X-Embodiment开源数据集 【免费下载链接】open_x_embodiment 项目地址: https://gitcode.com/gh_mirrors/op/open_x_embodiment 想要快速入门机器人学习领域?Open X-Embodiment为你提供了一个完整的机器人学习开…...
3个核心功能+5个实战技巧:用B站神奇弹幕彻底解放你的直播双手
3个核心功能5个实战技巧:用B站神奇弹幕彻底解放你的直播双手 【免费下载链接】MagicalDanmaku 本仓库及所有相关项目已永久停止开发、维护和任何形式的分发。 项目地址: https://gitcode.com/gh_mirrors/bi/MagicalDanmaku 你是否还在直播时手忙脚乱地回复弹…...
Steam Deck Tools 终极指南:让 Windows 掌机体验焕然一新
Steam Deck Tools 终极指南:让 Windows 掌机体验焕然一新 【免费下载链接】steam-deck-tools (Windows) Steam Deck Tools - Fan, Overlay, Power Control and Steam Controller for Windows 项目地址: https://gitcode.com/gh_mirrors/st/steam-deck-tools …...
基于ARM9工业平板与Linux的水质在线监测系统开发实践
1. 项目概述:当工业平板电脑遇上水质监测在环保、水产养殖、市政水务这些领域里,数据就是眼睛。过去,我们看水质,得靠人拿着采样瓶,一趟趟跑现场,再送回实验室,等上半天甚至几天才能拿到一份报告…...
抖音无水印视频下载技术深度解析:双架构设计与性能优化方案
抖音无水印视频下载技术深度解析:双架构设计与性能优化方案 【免费下载链接】douyin_downloader 抖音短视频无水印下载 win编译版本下载:https://www.lanzous.com/i9za5od 项目地址: https://gitcode.com/gh_mirrors/dou/douyin_downloader 抖音无…...
别再只烧SD卡了!IMX6ULL的BOOT_CFG引脚配置详解(附正点原子核心板电路图)
IMX6ULL启动配置全解析:从BOOT_CFG引脚到多介质启动实战 当你在深夜调试IMX6ULL开发板时,是否遇到过这样的困境——明明按照教程操作,系统却始终无法从EMMC启动?问题的根源往往藏在那些容易被忽略的硬件细节中。今天,我…...
