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

【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 识别后的文本框、可复制文本组件

需求 后面返回解析后的文本和四角坐标&#xff0c;在图片上渲染成框&#xff0c;并且可复制。图片还可以缩放、拖拽 实现 这里要重点讲下关于OCR文本框的处理&#xff1a; 因为一些文字可能是斜着放的&#xff0c;所有我们要特殊处理&#xff0c;根据三角函数来计算出它的偏…...

Linux系统运维脚本:批量创建linux用户和密码(读取文件中的账号和密码来批量创建用户)

目 录 一、要求 二、解决方案 &#xff08;一&#xff09;解决思路 &#xff08;二&#xff09;方案 三、脚本程序实现 &#xff08;一&#xff09;脚本代码和解释 1、脚本代码 2、代码解释 &#xff08;二&#xff09;脚本验证 1、脚本编辑 2、给予执行权…...

重力坝廊道量水堰计与堰板安装技术指南

在水利工程中&#xff0c;重力坝廊道量水堰计的安装是确保水资源有效监测与管理的关键环节。本文将详细阐述量水堰计及量水堰板的安装方法&#xff0c;以确保安装质量&#xff0c;提高水资源利用效率。 一、量水堰计的安装位置 量水堰计应安装在堰板的上游&#xff0c;距离堰板…...

ButterKnife实现之Android注解处理器使用教程

ButterKnife实现之Android注解处理器使用教程 1、新建一个注解 1.1、编译时注解 创建注解所需的元注解Retention包含3个不同的值&#xff0c;RetentionPolicy.SOURCE、RetentionPolicy.CLASS、RetentionPolicy.RUNTIME。这3个值代表注解不同的保留策略。 使用RetentionPolic…...

【哈希】Leetcode 128. 最长连续序列 【中等】

最长连续序列 给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。请你设计并实现时间复杂度为 O(n) 的算法解决此问题。示例 1&#xff1a;输入&#xff1a;nums [100,4,200,1,3,2]输出&#x…...

回溯是怎么回事(算法村第十八关青铜挑战)

组合 77. 组合 - 力扣&#xff08;LeetCode&#xff09; 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [[2,4],[3,4],[2,3],[1,2],[1,3],…...

向爬虫而生---Redis 探究篇5<Redis集群刨根问底(1)>

前言: Redis集群是一种可靠和高性能的分布式数据库解决方案。随着互联网的迅速发展和数据规模的增长,传统的单机Redis已经无法满足大规模应用的需求。Redis集群的出现填补了这一空白,提供了更高的可扩展性和容错性。 大家都知道,Redis是一种基于内存的高性能键值存储数据库,…...

系统集成Prometheus+Grafana

根据产品需求在自己的系统中添加一个系统监控的页面&#xff0c;其中有主机信息的显示&#xff0c;也有一些业务信息的显示。调研后的方案是 主机信息通过Prometheus采集和存储&#xff0c;业务信息通过自己系统的调度任务统计后存储在Mysql中&#xff0c;使用Grafana对接Prome…...

实例驱动计算机网络

文章目录 计算机网络的层次结构应用层DNSHTTP协议HTTP请求响应过程 运输层TCP协议TCP协议面向连接实现TCP的三次握手连接TCP的四次挥手断开连接 TCP协议可靠性实现TCP的流量控制TCP的拥塞控制TCP的重传机制 UDP协议 网际层IP协议&#xff08;主机与主机&#xff09;IP地址的分类…...

Unity 报错:SSL CA certificate error

使用UnityWebRequest时出现如下报错&#xff1a; SSL CA certificate error Curl error 60: Cert verify failed: UNITYTLS_X509VERIFY_FLAG_USER_ERROR1 原因&#xff1a; 证书验证失败 和 SSL CA证书错误 解决方法&#xff1a; 创建一个如下的类&#xff1a; /// <…...

算法刷题Day1 | 704.二分查找、27.移除元素

目录 0 引言1 二分查找1.1 我的解题1.2 修改后1.3 总结 2 移除元素2.1 暴力求解2.2 双指针法&#xff08;快慢指针&#xff09; &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;算法专栏&#x1f4a5; 标题&#xff1a;代码随想录算法训练营第一天…...

大数据技术学习笔记(五)—— 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金三银四必看前端面试题&#xff01;2w字精品&#xff01;简答版 金三银四黄金期来了 想要跳槽的小伙伴快来看啊 面试题 基于您给出的方向&#xff0c;我将为您生成20个面试题和答案。请注意&#xff0c;由于面试题的答案可能因个人经验和理解而…...

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安装失败的过程中&#xff0c;causal-conv1d安装报错为连接超时 key word: vision mamba&#xff0c; DL &#xff0c;深度学习 &#xff0c;mamba unet&#xff0c;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++

题目 思路 “两蚂蚁碰面会掉头&#xff0c;若其中一只蚂蚁感冒了&#xff0c;会把感冒传染给碰到的蚂蚁”&#xff0c;这句话看作是“两蚂蚁碰面会互相穿过&#xff0c;只是把感冒的状态传给了另一只蚂蚁”&#xff0c;因为哪只蚂蚁感冒了并不是题目的重点&#xff0c;重点是有…...

python Plotly可视化

文章目录 Plotly常用函数PolarPlotlymake_subplotsadd_tracego.Scatterpolarglupdate_tracesupdate_layout综合示例 完整版 Python在数据可视化方面有着丰富的库和函数&#xff0c;其中一些常用的库包括 Matplotlib、Seaborn、Plotly、Bokeh等。 Plotly是一个交互式绘图库&…...

刷题第10天

代码随想录刷题第10天 |● 239. 滑动窗口最大值 ● 347.前 K 个高频元素 239. 滑动窗口最大值 唉&#xff0c;好难&#xff0c;先记个思路吧 class Solution { private:class MyQueue { //单调队列&#xff08;从大到小&#xff09;public:deque<int> que; // 使用deq…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…...