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

news2024/10/6 8:32:02

可用业务场景

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

需求

后台返回一张图片或者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.coloradmin.cn/o/942181.html

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

相关文章

java-便签

--其实最痛的。不是离别。而是离别后的那些回忆。 java length( ) javalength中文占多长 1.一个中文字符或符号 2 个字节&#xff0c;一个英文字符或符号 1 个字节。 System.out.println("abc你好&#xff0c;".getBytes("gbk").length); System.out.pr…

Nuxt 菜鸟入门学习笔记四:静态资源

文章目录 public 目录assets 目录全局样式导入 Nuxt 官网地址&#xff1a; https://nuxt.com/ Nuxt 使用以下两个目录来处理 CSS、fonts 和图片等静态资源&#xff1a; public 目录 public 目录用作静态资产的公共服务器&#xff0c;可通过应用程序定义的 URL 公开获取。 换…

nvm安装及使用说明

1.说明&#xff1a; nvm 一个nodejs版本管理工具&#xff01; 2.官网&#xff1a;https://nvm.uihtm.com/ 3.卸载node.js&#xff08;没安装的话忽略&#xff09; 4.下载 链接&#xff1a;https://nvm.uihtm.com/nvm-1.1.10-setup.zip 5.nvm安装 卸载之前的node后安装nvm…

<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> /…

外部库/lib/maven依赖项 三者关系

外部库(存放项目初始配置的jar包)(它的文件夹里并没有包含lib文件夹的引的外部的依赖的jar包) lib(存放外部导入到项目的依赖的jar包) maven依赖项(管理项目所有的jar包依赖) 三者存放jar包的关系 项目所依赖的全部的jar包 maven依赖项的jar包 外部库中的jar包 lib中的…

基于STM32的酒精浓度检测报警防酒驾仿真设计(仿真+程序+讲解视频)

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

Oracle创建控制列表ACL(Access Control List)

Oracle创建控制列表ACL&#xff08;Access Control List&#xff09; Oracle ACL简介一、先登陆163邮箱设置开启SMTP。二、Oracle ACL控制列表处理&#xff08;一&#xff09;创建ACL&#xff08;create_acl&#xff09;&#xff08;二&#xff09;添加ACL权限&#xff08;add_…

2023热门短剧小剧场APP小程序系统介绍

迈特的短剧saas项目买来能干什么 系统上线推广已经半个月&#xff0c;很多朋友还不懂这项目是干什么的&#xff0c;我来给大家讲一下我所见识的&#xff08;非专业见解&#xff0c;说错了见谅&#xff09; 玩法由来 这种热门短剧玩法在去年就已经出现了&#xff0c;但是今年20…

13.毛玻璃动画特效

效果 源码 <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Glassmorphism Animation Effects</title><link rel="stylesheet" href="style.css"> </head> &…

最新AI创作系统ChatGPT源码+详细图文部署教程/支持GPT-4/AI绘画/H5端/Prompt知识库/思维导图生成

一、AI系统 如何搭建部署AI创作ChatGPT系统呢&#xff1f;小编这里写一个详细图文教程吧&#xff01;SparkAi使用Nestjs和Vue3框架技术&#xff0c;持续集成AI能力到AIGC系统&#xff01; 1.1 程序核心功能 程序已支持ChatGPT3.5/GPT-4提问、AI绘画、Midjourney绘画&#xf…

sql:SQL优化知识点记录(五)

&#xff08;1&#xff09;explain之例子 &#xff08;2&#xff09;索引单表优化案例 上面的功能已经实现&#xff0c;但是分析功能&#xff0c; 使用explain分析这条sql&#xff1a; 发现type为All Extra&#xff1a;有Using filesort &#xff08;文件内排序&#xff09; 这…

Kubernetes(k8s)当中安装并使用ingress暴露应用

Kubernetes当中安装并使用ingress暴露应用 为什么需要Ingress前期准备集群准备LoadBalancer准备 安装Ingress-Nginx下载地址v1.3.1v1.8.1 修改文件v1.3.1v1.8.1修改ingress服务类型配置 执行安装 部署应用通过ingress-nginx暴露应用部署ingress的yaml文件v1.3.1v1.8.1 为什么需…

E9—TEMAC IP实现千兆网口UDP传输2023-08-28

1.关于IP收费的问题 Tri Mode Ethernet MAC是收费IP&#xff0c;打开IP后&#xff0c;当左下角显示Bought IP license available则IP可用。 2.功能说明 应用搭建的场景是&#xff0c;上位机发送数据&#xff0c;首先发起arp请求&#xff0c;随后下位机给出arp应答响应&#…

设计模式—职责链模式(Chain of Responsibility)

目录 思维导图 什么是职责链模式&#xff1f; 有什么优点呢&#xff1f; 有什么缺点呢&#xff1f; 什么场景使用呢&#xff1f; 代码展示 ①、职责链模式 ②、加薪代码重构 思维导图 什么是职责链模式&#xff1f; 使多个对象都有机会处理请求&#xff0c;从而避免请…

【计算机网络】OSI 七层网络参考模型

OSI&#xff08;Open Systems Interconnection&#xff09;七层网络参考模型是一种用于描述计算机网络通信的框架&#xff0c;将网络通信划分为七个不同的层次&#xff0c;每个层次负责不同的功能。 以下为 OSI 七层网络参考模型的简单表格&#xff1a; --------------------…

Java注解—Annotation

Java注解——Annotation 一、概念 注解也是Java中一种比较特殊的存在&#xff0c;一般可以声明在任何一个位置&#xff0c;用于给我们的代码提供一些说明或者提供一些功能。 Override Deprecated 二、注解使用一般分为三种情况的注解 1、只是用来进行解释说明的注解&#x…

使用 Amazon Lambda 进行无服务器计算:云架构中的一场革命

引言 十年前,无服务器架构还像是痴人说梦。不再如此了! 有了 Amazon Lambda,我们现在可以建构和运行应用程序而不需要考虑服务器。云供应商会无缝地处理所有服务器的供应、扩展和管理。我们只需要关注代码。 这为云部署带来了前所未有的敏捷性、自动化和优化。但是,要发挥它的…

如何解决索引分裂问题?

索引分裂 索引块快写满时就会发生索引分裂&#xff0c;索引分裂分为两种情况&#xff0c;55和91&#xff1a; 索引分裂和enq: TX - index contension等待事件的区别 无论是55还是91&#xff0c;都是数据增多后索引的正常行为&#xff0c;索引分裂是业务数据量增大导致索引增大…

机器学习-神经网络(西瓜书)

神经网络 5.1 神经元模型 在生物神经网络中&#xff0c;神经元之间相互连接&#xff0c;当一个神经元受到的外界刺激足够大时&#xff0c;就会产生兴奋&#xff08;称为"激活"&#xff09;&#xff0c;并将剩余的"刺激"向相邻的神经元传导。 神经元模型…

Cento7 Docker-compose安装RabbitMQ

RabbitMQ是一个消息中间件&#xff0c;是用Erlang语言编写的。RabbitMQ据说具有良好的性能和时效性&#xff0c;同时还能够非常好的支持集群和负载部署&#xff0c;非常适合在较大规模的分布式系统中使用。接下来我们就以docker形式安装。 1.先安装docker环境 yum -y install…