【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…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...
LUA+Reids实现库存秒杀预扣减 记录流水 以及自己的思考
目录 lua脚本 记录流水 记录流水的作用 流水什么时候删除 我们在做库存扣减的时候,显示基于Lua脚本和Redis实现的预扣减 这样可以在秒杀扣减的时候保证操作的原子性和高效性 lua脚本 // ... 已有代码 ...Overridepublic InventoryResponse decrease(Inventor…...
