高亮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) => (
            <div
              className={styles.rectItem}
              key={index}
              data-key={`generate${index}`}
            >
              <Page
                pageNumber={1}
                width={fileSize?.[0]}
                height={fileSize?.[1]}
                onRenderSuccess={onPageLoadSuccess}
              />
              <div className={styles.coverTop} style={{ height: i[1] }} />
              <div
                className={styles.coverRight}
                style={{
                  left: i[0] + i[2],
                  top: i[1],
                  height: i[3],
                }}
              />
              <div
                className={styles.coverBottom}
                style={{ top: i[1] + i[3] }}
              />
              <div
                className={styles.coverLeft}
                style={{ width: i[0], top: i[1], height: i[3] }}
              />
            </div>
          ))}
        </Document>
      )}

      {/* img */}
      {fileType === "img" &&
        rects.map((i, index) => (
          <div
            className={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] }} />
            <div
              className={styles.coverRight}
              style={{
                left: i[0] + i[2],
                top: i[1],
                height: i[3],
              }}
            />
            <div className={styles.coverBottom} style={{ top: i[1] + i[3] }} />
            <div
              className={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.mfbz.cn/a/98999.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

UDP 广播

一、UDP 通信图解 UDP通信、本地套接字_呵呵哒(&#xffe3;▽&#xffe3;)"的博客-CSDN博客https://blog.csdn.net/weixin_41987016/article/details/132523536?spm1001.2014.3001.5501 #include <sys/types.h> #include <sys/socket > ssize_t sendto(in…

【校招VIP】前端算法考点之大数据相关

考点介绍&#xff1a; 大数据的关键技术分为分析技术和处理技术&#xff0c;可用于大数据分析的关键技术主要包括A/B测试&#xff0c;关联规则挖掘&#xff0c;数据挖掘&#xff0c;集成学习&#xff0c;遗传算法&#xff0c;机器学习&#xff0c;自然语言处理&#xff0c;模式…

计算机视觉-YOYO-

目录 计算机视觉-YOYO 目标检测发展历程 区域卷积神经网络(R-CNN) Fast R-CNN Mask R-CNN模型 比如SSD、YOLO(1, 2, 3)、R-FCN 目标检测基础概念 边界框、锚框和交并比 边界框&#xff08;bounding box&#xff09; 锚框&#xff08;Anchor box&#xff09; 交并比 …

Java中的Reference

1. 常用四种引用 快速记忆法&#xff1a;“硬(俗称的强引用) --> 软(SoftReference) --> 弱(WeakReference) --> 虚(PhantomReference)” 此处将常说的“强引用”记忆成“硬引用”可以对应到次席的“软引用”&#xff08;反义词&#xff1a;硬-软&#xff09;这样更容…

Flink 如何定位反压节点?

分析&回答 Flink Web UI 自带的反压监控 —— 直接方式 Flink Web UI 的反压监控提供了 Subtask 级别的反压监控。监控的原理是通过Thread.getStackTrace() 采集在 TaskManager 上正在运行的所有线程&#xff0c;收集在缓冲区请求中阻塞的线程数&#xff08;意味着下游阻…

Dockerfile 使用教程

1.Dockerfile 1.1 什么是Dockerfile Dockerfile可以认为是 Docker镜像的描述文件&#xff0c;是由一系列命令和参数构成的脚本 。主要作用是 用来构建docker镜像的构建文件 。 通过架构图可以看出通过DockerFile可以直接构建镜像 1.2 Dockerfile解析过程 构建镜像步骤&#xf…

2023年高教社杯数学建模思路 - 案例:感知机原理剖析及实现

文章目录 1 感知机的直观理解2 感知机的数学角度3 代码实现 4 建模资料 # 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 感知机的直观理解 感知机应该属于机器学习算法中最简单的一种算法&#xff0c;其…

LLM - LLaMA-2 获取文本向量并计算 Cos 相似度

目录 一.引言 二.获取文本向量 1.hidden_states 与 last_hidden_states ◆ hidden_states ◆ last_hidden_states 2.LLaMA-2 获取 hidden_states ◆ model config ◆ get Embedding 三.获取向量 Cos 相似度 1.向量选择 2.Cos 相似度 3.BERT-whitening 特征白化 …

.ssh文件夹下缺失known_hosts文件

.ssh文件夹下缺失known_hosts文件 先确认工蜂或github 添加了git生成的密钥 然后 桌面打开git bash 1、执行ssh -T gitgitlab.com 2、输入yes

b站手机缓存文件转MP4

b站缓存的文件 音频、视频、弹幕是分开的 这里我只用到了音频和视频所以只介绍这一部分 b站的缓存视频文件和路径结构如下 默认缓存路径 内部存储\Android\data\tv.danmaku.bilil\download\89720189 文件夹结构 文件夹 c_738583 这是单个视频的缓存文件夹 进入c_738583文件夹…

电脑可以上网,微信都可以用,但浏览器打不开网页

可以试试设置DNS&#xff08;其他windows版本步骤&#xff09;&#xff1a; 1.打开控制面板 2.网络和Internet 3.查看网络计算机和设备 4.按照下图步骤&#xff1a; 5.按下图进行

Unity 之 方括号[ ] 的用法以及作用

文章目录 在Unity中&#xff0c;方括号 [ ] 通常用于表示属性、特性&#xff08;Attributes&#xff09;或者元数据&#xff08;Metadata&#xff09;。这些标记提供了附加信息&#xff0c;可以用于修改类、方法、字段等的行为或者在编辑器中进行设置。 以下是一些常见的用法&…

基于stm32的烟雾浓度检测报警proteus仿真设计(仿真+程序+讲解)

基于STM32的烟雾浓度检测报警仿真设计(仿真程序讲解&#xff09; 1.主要功能2.仿真3. 程序4. 资料清单&下载链接 基于STM32的烟雾浓度检测报警仿真设计(仿真程序讲解&#xff09; 仿真图proteus 8.9 程序编译器&#xff1a;keil 5 编程语言&#xff1a;C语言 设计编号&a…

Huggingface托管机器学习模型及API提供

推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 我想在我的网络和移动应用程序中使用机器学习模型&#xff0c;但要做到这一点&#xff0c;我必须在某个地方托管我的机器学习应用程序。 托管预先训练的 ML 模型称为推理。 我只想添加一些 Python ML 代码并快速获得 REST…

C语言:字符函数和字符串函数(一篇拿捏字符串函数!)

目录 求字符串长度&#xff1a; 1. strlen(字符串长度) 长度不受限制函数&#xff1a; 2. strcpy(字符串拷贝) 3. strcat(字符串追加) 4. strcmp(字符串比较) 长度受限制函数&#xff1a; 5. strncpy(字符串拷贝) 6. strncat(字符串追加) 7. strncmp(字符串比较) 字…

MR混合现实汽车维修情景实训教学演示

MR混合现实技术应用于汽车维修课堂中&#xff0c;能够赋予学生更加真实&#xff0c;逼真地学习环境&#xff0c;让学生在情景体验中不断提高自己的专业能力。 MR混合现实汽车维修情景实训教学演示具体体现在&#xff1a; 1. 虚拟维修指导&#xff1a;利用MR技术&#xff0c;可…

upgrade pip报错:def read(rel_path: str) -> str: syntaxerror

命令行执行以下命令就可以大功告成! wget https://bootstrap.pypa.io/pip/2.7/get-pip.py python get-pip.py pip install --upgrade setuptools最后大功告成:

Vue3+ts封装一个简单版的Message组件

Vue3ts封装一个Message组件 项目中需要使用信息提示框的功能&#xff0c;ui组件库使用的是字节的arco-design-vue。看了一下&#xff0c;现有的Message不满足要是需求&#xff0c;直接使用message组件的话&#xff0c;改样式太麻烦。Notification组件样式倒是符合了&#xff0c…

使用maven创建springboot项目

创建maven快速启动项目 命令行或者idea、eclipse快捷创建也可以 pom.xml下project项目下导入springboot 父工程 <!--导入springboot 父工程--> <parent><artifactId>spring-boot-starter-parent</artifactId><groupId>org.springframework.bo…
最新文章