高亮img、pdf重点部分(html2canvas、pdfjs-dist、react-pdf)

可用业务场景

报销单据审批中,高亮发票部分

需求

后台返回一张图片或者pdf、返回一组坐标,坐标类型[number,number,number,number],分别代表了x、y、width、height。需要根据坐标在图片上高亮出来坐标位置。如下图
高亮的坐标是:

const rect: Rect[] = [[100, 100, 200, 200],[200, 300, 200, 200],
];

在这里插入图片描述
在这里插入图片描述

技术选型

  • dom转成图片:html2canvas
  • pdf预览:pdfjs-dist、react-pdf
  • 遮照:纯css实现(四个绝对定位的dom)

这里的react-pdf使用的是V4,用来兼容IE11
遮照也可以换成是一个矩形框,看具体需求,我这里的需求是遮照高亮

代码

组件部分

/** @Author: Do not edit* @Date: 2023-08-25 13:48:06* @LastEditors: atwlee* @LastEditTime: 2023-08-28 14:08:34* @Descripttion:* @FilePath: /test/src/pages/generate.tsx*/import { FC, useEffect, useRef } from "react";
import styles from "./index.modules.less";
import html2canvas from "html2canvas";
import { Document, Page, pdfjs } from "react-pdf";pdfjs.GlobalWorkerOptions.workerSrc = new URL("pdfjs-dist/build/pdf.worker.min.js",import.meta.url
).toString();export type Rect = [number, number, number, number];interface GenerateProps {fileUrl: string;rects: Rect[];onGenerateCallback: (imgs: string[]) => void;fileType: "img" | "pdf";fileSize?: [number, number];
}const Index: FC<GenerateProps> = (props) => {const { fileUrl, rects, onGenerateCallback, fileType, fileSize } = props;const divRef = useRef<HTMLDivElement>(null);const handleGenerateImg = () => {const results: string[] = [];rects.forEach((item, index) => {html2canvas(divRef.current!.querySelector(`[data-key="generate${index}"]`)!,{useCORS: true,}).then((canvas) => {results.push(canvas.toDataURL("image/png"));results.length === rects.length && onGenerateCallback(results);});});};const pdf2img = useRef<string[]>([]);const onPageLoadSuccess = () => {rects.forEach((item, index) => {html2canvas(divRef.current!.querySelector(`[data-key="generate${index}"]`)!,{useCORS: true,}).then((canvas) => {pdf2img.current.push(canvas.toDataURL("image/png"));if (pdf2img.current.length === rects.length) {onGenerateCallback(pdf2img.current);pdf2img.current = [];}});});};useEffect(() => {fileType === "img" && handleGenerateImg();}, [fileUrl, rects, fileType]);return (<div ref={divRef} className={styles.contanier}>{/* pdf */}{fileType === "pdf" && (<Document file={fileUrl}>{rects.map((i, index) => (<divclassName={styles.rectItem}key={index}data-key={`generate${index}`}><PagepageNumber={1}width={fileSize?.[0]}height={fileSize?.[1]}onRenderSuccess={onPageLoadSuccess}/><div className={styles.coverTop} style={{ height: i[1] }} /><divclassName={styles.coverRight}style={{left: i[0] + i[2],top: i[1],height: i[3],}}/><divclassName={styles.coverBottom}style={{ top: i[1] + i[3] }}/><divclassName={styles.coverLeft}style={{ width: i[0], top: i[1], height: i[3] }}/></div>))}</Document>)}{/* img */}{fileType === "img" &&rects.map((i, index) => (<divclassName={styles.rectItem}key={index}data-key={`generate${index}`}><img src={fileUrl} width={fileSize?.[0]} height={fileSize?.[1]} /><div className={styles.coverTop} style={{ height: i[1] }} /><divclassName={styles.coverRight}style={{left: i[0] + i[2],top: i[1],height: i[3],}}/><div className={styles.coverBottom} style={{ top: i[1] + i[3] }} /><divclassName={styles.coverLeft}style={{ width: i[0], top: i[1], height: i[3] }}/></div>))}</div>);
};export default Index;

使用

/** @Author: Do not edit* @Date: 2023-08-24 15:57:05* @LastEditors: atwlee* @LastEditTime: 2023-08-28 14:13:37* @Descripttion:* @FilePath: /test/src/pages/index.tsx*/
import { useState } from "react";
import Generate from "./generate";
import type { Rect } from "./generate";
import yayJpg from "./yay.jpg";
import pdfUrl from "./redv2.pdf";const rect: Rect[] = [[100, 100, 200, 200],[200, 300, 200, 200],
];export default function HomePage() {const [imgs, setImgs] = useState<string[]>([]);const onGenerateCallback = (img: string[]) => {setImgs(img);};const hiddenStyle = { height: 0, overflow: "hidden" };return (<div><h2>Yay! Welcome to umi!</h2><div style={hiddenStyle}><Generate// fileType="pdf"fileType="img"// fileUrl={pdfUrl}// fileUrl={'https://www.sdta.cn/pdf/e-map.pdf'}fileUrl={yayJpg}// fileUrl={//   "https://img1.baidu.com/it/u=2488875768,1454762303&fm=253&fmt=auto&app=120&f=JPEG?w=1422&h=800"// }rects={rect}onGenerateCallback={onGenerateCallback}/></div>{imgs.map((i, index) => {return <img src={i} key={index} alt="" />;})}</div>);
}

demo源码

PS

图片的话不用在意实际的宽度和高度,当然如果有更好。pdf不知道需不需要实际的宽度和高度,这里抛出去了fileSize的属性,demo里没有使用,没有测试。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/57326.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux————keepalived+LVS(DR模式)

一、作用 使用keepalived解决LVS的单点故障 高可用集群 二、 调度器配置 环境 两台LVS服务 一主一备 两台web服务 采用nginx &#xff08;实现LVS负载均衡&#xff09; 服务ip 主LVS 192.168.100.3 备LVS 192.168.100.6 web1 192.…

创作2周年纪念日-特别篇

创作2周年纪念日-特别篇 1. 与CSDN的机缘2. 收获3. 憧憬 1. 与CSDN的机缘 很荣幸&#xff0c;在大学时候&#xff0c;能够接触到CSDN这样一个平台&#xff0c;当时对嵌入式开发、编程、计算机视觉等内容比较感兴趣。后面一个很偶然的联培实习机会&#xff0c;让我接触到了Pych…

中国平台软件市场研究报告:OceanBase为金融行业国产分布式数据库销售额第一

近日&#xff0c;《2022-2023年度中国平台软件市场研究报告》&#xff08;以下简称“报告”&#xff09;发布&#xff0c;报告对包括数据库、操作系统等在内的平台软件市场发展进行了分析。报告指出&#xff0c;在对平台软件需求增长最快的金融行业&#xff0c;OceanBase已占据…

音频母带制作::AAMS V4.0 Crack

自动音频母带制作简介。 使用 AAMS V4 让您的音乐听起来很美妙&#xff01; 作为从事音乐工作的音乐家&#xff0c;您在向公众发布材料时需要尽可能最好的声音&#xff0c;而为所有音频扬声器系统提供良好的商业声音是一项困难且耗时的任务。AI掌握的力量&#xff01; 掌控您…

Android studio APK切换多个摄像头(Camera2)

1.先设置camera的权限 <uses-permission android:name"android.permission.CAMERA" /> 2.布局 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"and…

Spring redis使用报错Read timed out排查解决

文章目录 使用场景报错信息解决方式 使用场景 我们使用redis作为缓存服务&#xff0c;缓存一些业务数据&#xff0c;如路口点位信息、渠化信息、设备信息等有一些需要实时计算的数据&#xff0c;缓存在redis里&#xff0c;如实时信号周期相位、周期内过车数量等有需要不同服务…

docker高级(redis集群三主三从)

1. 新建6个docker容器redis实例 docker run -d --name redis-node-1 --net host --privilegedtrue -v /redis/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381docker run -d --name redis-node-2 --net host --privilegedtrue -v /…

JVM 访问对象的两种方式

Java 程序会通过栈上的 reference 数据来操作堆上的具体对象。由于 reference 类型在《Java 虚拟机规范》里面只规定了它是一个指向对象的引用&#xff0c;并没有定义这个引用应该通过什么方式去定位、访问到堆中对象的具体位置&#xff0c;所以对象访问方式也是由虚拟机实现而…

酒店资产如何管理提升资产利用效率

酒店资产管理系统是一种专门为酒店行业设计的管理软件&#xff0c;可以帮助酒店实现资产的全生命周期管理。一个好的酒店资产管理系统应该具备以下功能&#xff1a;  资产登记&#xff1a;可以对酒店的各种资产进行登记&#xff0c;包括房间、家具、设备等&#xff0c;记录资…

EasyExcel+POI制作带有有效性校验及下拉联动的Excel模板

文章目录 1.背景2.实现功能的Excel特性2.1.特性介绍2.2.下拉框联动2.3.单元格自动匹配Id2.4.错误提示 3.代码实现3.1.基础流程代码3.2.名称管理器配置3.3.有效性配置3.4.函数填充3.5.其他补充 4.总结 1.背景 最近在做一个CRM系统的人员销售目标导入的相关需求&#xff0c;需要…

初试Eureka注册中心

Eureka是spring cloud中的一个负责服务注册与发现的组件。遵循着CAP理论中的A(可用性)P(分区容错性)。一个Eureka中分为eureka server和eureka client。其中eureka server是作为服务的注册与发现中心。 搭建eureka服务 引入eureka依赖 引入SpringCloud为eureka提供的starter依…

Day48|leetcode 198.打家劫舍、213.打家劫舍II、打家劫舍|||

leetcode 198.打家劫舍 题目链接&#xff1a;198. 打家劫舍 - 力扣&#xff08;LeetCode&#xff09; 视频链接&#xff1a;动态规划&#xff0c;偷不偷这个房间呢&#xff1f;| LeetCode&#xff1a;198.打家劫舍_哔哩哔哩_bilibili 题目概述 你是一个专业的小偷&#xff0c;…

最小化安装移动云大云操作系统--BCLinux-for-Euler-22.10-everything-x86_64-230316版

CentOS 结束技术支持&#xff0c;转为RHEL的前置stream版本后&#xff0c;国内开源Linux服务器OS生态转向了开源龙蜥和开源欧拉两大开源社区&#xff0c;对应衍生出了一系列商用Linux服务器系统。BCLinux-for-Euler-22.10是中国移动基于开源欧拉操作系统22.03社区版本深度定制的…

【微服务】06-安全问题

文章目录 1.反跨站请求伪造1.1 攻击过程1.2 攻击核心1.3 如何防御1.4 使用AntiforgeryToken机制来防御用到的类 2. 防开发重定向共计2.1 攻击过程2.2 攻击核心2.3 防范措施 3.防跨站脚本3.1 攻击过程3.2 防范措施 4.跨域请求4.1 同源与跨域4.2 CORS过程4.2 CORS是什么4.3 CORS请…

<C++> SSE指令集

SSE指令集 include库 #include <mmintrin.h> //MMX #include <xmmintrin.h> //SSE(include mmintrin.h) #include <emmintrin.h> //SSE2(include xmmintrin.h) #include <pmmintrin.h> //SSE3(include emmintrin.h) #include <tmmintrin.h> /…

Zabbix 5.0 媒体介质 邮箱配置例子

QQ企业邮箱 参考&#xff1a;zabbix 腾讯企业邮箱配置图_harveymomo的博客-CSDN博客

Linux下的系统编程——vim/gcc编辑(二)

前言&#xff1a; 在Linux操作系统之中有很多使用的工具&#xff0c;我们可以用vim来进行程序的编写&#xff0c;然后用gcc来生成可执行文件&#xff0c;最终运行程序。下面就让我们一起了解一下vim和gcc吧 目录 一、vim编辑 1.vim的三种工作模式 2.基本操作之跳转字符 &a…

无涯教程-机器学习 - 箱形图函数

Box和Whisker图(也简称为boxplots)是另一种有用的技术&#xff0c;可用于检查每个属性的分布情况。以下是此技术的特点- 它本质上是单变量的&#xff0c;总结了每个属性的分布。它为中间值(即中位数)画一条线。它将在25&#xff05;和75&#xff05;周围绘制一个框。它还会绘制…

UE4/5在蓝图细节面板中添加函数按钮(蓝图与c++的方法)

目录 在细节面板中添加按钮使用函数 蓝图的方法 事件 函数 效果 uec的方法 效果 在细节面板中添加按钮使用函数 很多时候&#xff0c;我们可以看到一些插件的actor类中&#xff0c;点击一下之后就可以实现如矩阵一样的效果。 实际上是因为其使用了函数来修改了蓝图中的数…

完美解决Ubuntu网络故障,连接异常,IP地址一直显示127.0.0.1

终端输入ifconfig显示虚拟机IP地址为127.0.0.1&#xff0c;具体输出内容如下&#xff1a; wxyubuntu:~$ ifconfig lo: flags73<UP,LOOPBACK,RUNNING> mtu 65536inet 127.0.0.1 netmask 255.0.0.0inet6 ::1 prefixlen 128 scopeid 0x10<host>loop txqueuelen …