网页转长图插件html2canvas【前端】

网页转长图插件html2canvas【前端】

  • 前言
  • 版权
  • 推荐
  • 网页转长图插件html2canvas【前端】
    • wkImageStorage
    • 流程
    • 使用
    • 后端
      • application.properties
      • WkConfig
      • ShareController
      • ImageCleanupTask
    • 前端
      • html2canvas.js
      • share.html
      • share.js
      • getShare.js
      • getShare.html
  • 最后

前言

2024-5-10 18:00:10

以下内容源自《【前端】》
仅供学习交流使用

版权

禁止其他平台发布时删除以下此话
本文首次发布于CSDN平台
作者是CSDN@日星月云
博客主页是https://jsss-1.blog.csdn.net
禁止其他平台发布时删除以上此话

推荐

网页转长图插件html2canvas【前端】

wkImageStorage

wkhtmltoimage 不能导出动态数据
在这里插入图片描述

流程

要实现网页转长图的功能,可以使用以下步骤和技术:

  1. 前端部分:
  • 创建一个按钮或链接,触发网页转长图的操作。
  • 使用 HTML2Canvas 库将当前网页内容转换为 canvas 元素。
  • 将 canvas 元素转换为图片,并拼接成长图。
  1. 后端部分:
  • 前端通过 AJAX 将转换后的图片数据发送到后端。
  • 后端接收到图片数据后保存为图片文件。
  1. 完整步骤:
  • 用户点击网页上的按钮触发网页转长图的操作。
  • 前端使用 HTML2Canvas 将当前网页内容转换为 canvas 元素。
  • 前端将 canvas 元素转换为图片数据。
  • 前端通过 AJAX 将图片数据发送到后端。
  • 后端接收到图片数据后保存为图片文件。
  • 后端返回图片文件的 URL 给前端。
  • 前端显示长图或提供下载链接给用户。
  1. 注意事项:
  • 转换过程可能会涉及到跨域问题,需要确保前后端的跨域设置正确。
  • HTML2Canvas 库的使用需要注意性能,避免转换过程过慢或耗时过长。
  • 图片文件的存储位置和命名需要考虑安全性和可维护性。

以上是设计网页转长图功能的一般步骤,具体实现过程可能会根据项目需求和技术栈有所不同。希望这些信息对你有帮助,如果有任何问题或需要进一步的指导,请随时告诉我。

使用

html2canvas使用教程

html2canvas快速使用

后端

application.properties

wk.image.storage=d:/eldhealth-work/data/wk-images
wk.image.max_storage_size=524288000

WkConfig

package com.jsss.configuration;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.io.File;

@Configuration
public class WkConfig {

    private static final Logger logger = LoggerFactory.getLogger(WkConfig.class);

    @Value("${wk.image.storage}")
    private String wkImageStorage;

    @PostConstruct
    public void init() {
        // 创建WK图片目录
        File file = new File(wkImageStorage);
        if (!file.exists()) {
            file.mkdir();
            logger.info("创建WK图片目录: " + wkImageStorage);
        }
    }

}

ShareController

package com.jsss.share.controller;

import com.jsss.common.BusinessException;
import com.jsss.common.ErrorCode;
import com.jsss.common.ResponseModel;
import com.jsss.common.Toolbox;
import com.jsss.utils.Constant;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.util.Base64Utils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.*;

@Controller
@CrossOrigin(origins = "${jsss.web.path}", allowedHeaders = "*", allowCredentials = "true")
public class ShareController implements Constant, ErrorCode {

    private static final Logger logger = LoggerFactory.getLogger(ShareController.class);

    @Value("${jsss.web.path}")
    private String domain;

    @Value("${server.servlet.context-path}")
    private String contextPath;

    @Value("${wk.image.storage}")
    private String wkImageStorage;



    @PostMapping("/uploadImage")
    @ResponseBody
    public ResponseModel uploadImage(String token,String imageData) {

        // 截取 base64 编码的部分
        String base64Data = imageData.substring(imageData.indexOf(",") + 1);

        // 解码Base64字符串为字节数组
        byte[] imageBytes = Base64Utils.decodeFromString(base64Data);

        // 文件名
        String fileName = Toolbox.getRandomString();

        // 保存字节数组为图片文件
        String imagePath = wkImageStorage + "/" +  fileName+ ".png";

        try (FileOutputStream fos = new FileOutputStream(imagePath)) {
            fos.write(imageBytes);
        } catch (IOException e) {
            e.printStackTrace();
            return new ResponseModel("Error saving image");
        }

        return new ResponseModel(fileName);

    }

    // 获取长图
    @RequestMapping(path = "/share/image/{fileName}", method = RequestMethod.GET)
    @ResponseBody
    public void getShareImage(@PathVariable("fileName") String fileName, HttpServletResponse response) {
        if (StringUtils.isBlank(fileName)) {
            throw new BusinessException(PARAMETER_ERROR,"文件名不能为空!");
        }
        File file = new File(wkImageStorage + "/" + fileName + ".png");

        if (!file.exists()) {
            throw new BusinessException(PARAMETER_ERROR,"文件不存在!");
        }

        response.setContentType("image/png");

        try {
            OutputStream os = response.getOutputStream();
            FileInputStream fis = new FileInputStream(file);
            byte[] buffer = new byte[1024];
            int b = 0;
            while ((b = fis.read(buffer)) != -1) {
                os.write(buffer, 0, b);
            }
        } catch (IOException e) {
            logger.error("获取长图失败: " + e.getMessage());
        }


    }

}

ImageCleanupTask

package com.jsss.share.component;

import com.jsss.share.controller.ShareController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.File;
import java.util.Arrays;
import java.util.Date;

@Component
public class ImageCleanupTask {

    private static final Logger logger = LoggerFactory.getLogger(ShareController.class);


    @Value("${wk.image.storage}")
    String DIRECTORY_PATH;
    @Value("${wk.image.max_storage_size}")
    long MAX_STORAGE_SIZE;

    @Scheduled(cron = "0 0 0 * * *") // 每天凌晨执行
    public void cleanupImages() {
        File directory = new File(DIRECTORY_PATH);
        if (!directory.exists()) {
            return; // 目录不存在,直接返回
        }

        long totalSize = 0;

        File[] files = directory.listFiles();
        if (files == null) {
            return; // 目录为空,直接返回
        }

        // 按文件最后修改时间从大到小排序
        Arrays.sort(files, (f1, f2) -> Long.compare(f2.lastModified(), f1.lastModified()));

        for (File file : files) {
            long fileSize = file.length();
            totalSize += fileSize;

            Date currentDate = new Date();
            Date fileDate = new Date(file.lastModified());
            boolean isBeforeToday = fileDate.before(currentDate);

            if (isBeforeToday || totalSize > MAX_STORAGE_SIZE) {
                file.delete();
                logger.info("删除图片: " + file.getName());
            }
        }
    }
}


前端

html2canvas.js

下载插件

npm install --save html2canvas

找到这个js,引入到项目中

share.html

测试页面

可以利用js把导出按钮添加到所有页面

$(document).ready(function() {
	
    // 创建要添加的<div>元素
    var content =
	
			<div class="nav navbar-nav navbar-right" id="share" style="padding; margin-right: 20px;">
				<button id="convertButton">导出</button>
			</div>
		`;
    
		$(".container-fluid").append(content);

	
});
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>老年人健康管理</title>
    <link rel="icon" href="#">
    <link rel="stylesheet" href="./bootstrap/css/bootstrap.min.css">
    <link rel="stylesheet" href="./css/common.css">
  </head>


  <body>
    <nav class="navbar navbar-default">
      <div class="container-fluid">
        <div class="navbar-header">
          <a class="navbar-brand" href="#" target="_blank">老年人健康管理</a>
        </div>
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
          <ul class="nav navbar-nav">
            <li><a href="home.html">首页</a></li>
            <li><a href="register.html">个人注册</a></li>
            <li class="active"><a href="javascript:void(0);">账户登录 <span class="sr-only">(current)</span></a></li>
          </ul>
        </div>
      </div>
    </nav>

    <div class="container">
      <button id="convertButton">导出</button>
    </div>
    
  </body>
  
  <script src="./bootstrap/js/jquery-3.5.1.min.js"></script>
  <script src="./bootstrap/js/bootstrap.min.js"></script>
  <script src="./js/common.js"></script>
  <script src="./js/user.js"></script>
  <script src="./share/js/html2canvas.js"></script>
  <script src="./share/js/share.js"></script>

</html>



share.js

// 绑定按钮点击事件
$(document).ready(function () {
    // 分享单击事件
    $("#convertButton").click(function (e) { 
        share(e);
    });
});

function share() {
    // 使用 HTML2Canvas 将当前网页内容转换为 canvas 元素
    html2canvas(document.documentElement).then(function(canvas) {
        // 将 canvas 转换为图片
        var imgData = canvas.toDataURL('image/png');
        
        $.ajax({
            type: 'POST',
            url: SERVER_PATH + "/uploadImage",
            data: {
                imageData: imgData
            },
            success: function(result) {
                var fileName = result.data;
                // 在新建标签页中打开 getShare 页面并传递文件名作为参数
                window.open('http://127.0.0.1:5500/getShare.html?fileName=' + fileName, '_blank');
            }
        });
    });
}



getShare.js

$(document).ready(function () {
    var fileName=$.getUrlParam("fileName");
    if(!fileName){
       false;
    }
    getShare(fileName);
});

function getShare(fileName){
    
  
    var imageUrl = SERVER_PATH + "/share/image/"+fileName;

    console.log(imageUrl);
            
    // 显示长图
    var imgElement = document.createElement('img');
    imgElement.style.width = '100%';
    imgElement.style.height = '100%';

    imgElement.src = imageUrl;
    document.body.appendChild(imgElement);
            
    // 提供下载链接给用户
    // var downloadLink = document.createElement('a');
    // downloadLink.href = imageUrl;
    // downloadLink.download = 'image_file.jpg';
    // downloadLink.innerHTML = '下载图片';
    // document.body.appendChild(downloadLink);
    
       
}

getShare.html

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>老年人健康管理</title>
    <link rel="icon" href="#">
    <link rel="stylesheet" href="./bootstrap/css/bootstrap.min.css">
    <link rel="stylesheet" href="./css/common.css">
  </head>


  <body>

   

  </body>
  
  <script src="./bootstrap/js/jquery-3.5.1.min.js"></script>
  <script src="./bootstrap/js/bootstrap.min.js"></script>
  <script src="./js/common.js"></script>
  <script src="./js/user.js"></script>
  <script src="./share/js/getShare.js"></script>

</html>



最后

2024-5-10 18:00:23

迎着日光月光星光,直面风霜雨霜雪霜。

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

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

相关文章

算法金 | Xorbits,一个超强的 Python 库

本文来源公众号“算法金”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;Xorbits&#xff0c;一个超强的 Python 库 1 Xorbits 库介绍 在数据科学和机器学习的世界里&#xff0c;处理大规模数据集和复杂计算的需求日益增长。 这…

YOLOv9最新改进系列:融合空间信息关注机制(SimAM)于YOLOv9网络,在通道之间和空间位置之间建立更加准确的关联,助力YOLOv9有效涨点!!!

YOLOv9最新改进系列&#xff1a;融合空间信息关注机制&#xff08;SimAM&#xff09;于YOLOv9网络&#xff0c;在通道之间和空间位置之间建立更加准确的关联,助力YOLOv9有效涨点&#xff01;&#xff01;&#xff01; 在此之前&#xff01;先恭喜两位家人&#xff01;&#xf…

uniapp下拉选择组件

uniapp下拉选择组件 背景实现思路代码实现配置项使用尾巴 背景 最近遇到一个这样的需求&#xff0c;在输入框中输入关键字&#xff0c;通过接口查询到结果之后&#xff0c;以下拉框列表形式展现供用户选择。查询了下uni-app官网和项目中使用的uv-ui库&#xff0c;没找到符合条…

sentinel搭建及使用

1.添加依赖&#xff08;版本可依赖于父pom&#xff09; SentinalResource注解&#xff1a; 添加依赖&#xff1a; blockhandler: fallback:

以Azure为例的SSO

由于文章的篇幅有限&#xff0c;无法将全部的代码贴上来&#xff0c;如想要看完整案例&#xff0c;请在公众号文章中留言(其他平台很少看…毕竟最近印度同事的UI组件库搞得我好烦) 1.关于SSO 单点登录又称之为SSO,全称为 Single Sign On &#xff0c;一般在多个应用系统中&…

文献速递:多模态深度学习在医疗中的应用--多模态深度学习用于阿尔茨海默病痴呆评估

Title 题目 Multimodal deep learning for Alzheimer’s disease dementia assessment 多模态深度学习用于阿尔茨海默病痴呆评估 01 文献速递介绍 全球每年新发痴呆症病例近1000万例&#xff0c;其中阿尔茨海默病&#xff08;AD&#xff09;最为常见。需要新的措施来改善因…

【快捷部署】023_HBase(2.3.6)

&#x1f4e3;【快捷部署系列】023期信息 编号选型版本操作系统部署形式部署模式复检时间023HBase2.3.6Ubuntu 20.04tar包单机2024-05-07 注意&#xff1a;本脚本非全自动化脚本&#xff0c;有2次人工干预&#xff0c;第一次是确认内网IP&#xff0c;如正确直接回车即可&#…

【6大模型让你的沟通汇报更有条理】项目管理常见问题大揭秘 03

6大模型让你的沟通汇报更有条理 虽然头脑中构思众多&#xff0c;一开口却发现空白一片&#xff1f; 工作表现出色&#xff0c;汇报时却总是支支吾吾不知从何说起&#xff1f; 生性腼腆&#xff0c;却难以避免需要站在众人面前发言&#xff1f; 阿道掐指一算&#xff1a;你需…

头歌实践教学平台:CG1-v2.0-直线绘制

第4关&#xff1a;直线光栅化-任意斜率的Bresenham画线算法 一.任务描述 1.本关任务 (1)根据直线Bresenham算法补全line函数以绘制白色直线&#xff0c;其中直线斜率为任意情况。 (2)当直线方程恰好经过P(x,y)和T(x,y1)的中点M时&#xff0c;统一选取直线上方的T点为显示的像…

springboot引入security,测试接口报Unauthorized

1、报错截图 2、当前项目pom文件引入security <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-security</artifactId><version>2.2.2.RELEASE</version> </dependency> 3、解决…

基于springboot实现毕业设计系统项目【项目源码+论文说明】

基于springboot实现毕业设计系统演示 摘要 在如今社会上&#xff0c;关于信息上面的处理&#xff0c;没有任何一个企业或者个人会忽视&#xff0c;如何让信息急速传递&#xff0c;并且归档储存查询&#xff0c;采用之前的纸张记录模式已经不符合当前使用要求了。所以&#xff…

MySQL —— 约束

一、概念介绍 MySQL是数据管理的最后一层防线&#xff0c;因此在对数据进行各种操作的时候&#xff0c;我们尽可能的从技术的角度去对用户进行各种合理的约束&#xff0c;使得各种数据的操作尽可能的合理&#xff0c;这就是约束的概念&#xff0c;本篇将整理常见的基本约束&am…

论文解读--Resolving Target Ambiguities in Automotive Radar Using DDMA Techniques

使用DDMA技术解决汽车雷达中的目标模糊 摘要 多普勒分多址(DDMA)是一种慢时相位编码技术&#xff0c;可以使用传统相控阵硬件实现多输入多输出(MIMO)雷达。然而&#xff0c;众所周知&#xff0c;DDMA会在接收到的多普勒频谱中引起模糊。虽然非对称DDMA已经被提出来缓解目标模糊…

基于Vant UI的微信小程序开发(随时更新的写手)

基于Vant UI的微信小程序开发✨ &#xff08;一&#xff09;悬浮浮动1、效果图&#xff1a;只要无脑引用样式就可以了2、页面代码3、js代码4、样式代码 &#xff08;二&#xff09;底部跳转1、效果图&#xff1a;点击我要发布跳转到发布的页面2、js代码3、页面代码4、app.json代…

SQL注入(sqli-labs第一关)

sqli-labs第一关 方法一&#xff1a;手工注入 来到第一关&#xff0c;图上说我们需要一个数字的参数 于是我们先手工注入?id1 and 11 跟?id1 and 12发现页面没有报错 每张截图上面页面中有select查询语句&#xff0c;这是我在第一关的源码中加上了echo "$sql ";…

Linux下安装mysql8.0(以tar.xz包安装--编译安装)

前言&#xff1a;原文在我的博客网站中&#xff0c;持续更新数通、系统方面的知识&#xff0c;欢迎来访&#xff01; Linux下安装mysql8.0&#xff08;以tar.xz包安装--编译安装&#xff09;https://myweb.myskillstree.cn/126.html 目录 一、下载对应自己glic版本的MySQL …

VS远程调试

因为是做工厂应用的客制化项目&#xff0c;在客户现场出现异常&#xff0c;本地又很难复现&#xff0c;而且重启软件可能又自动恢复了&#xff0c;此时可以用VisualStudio自带的远程调试功能进行调试&#xff0c;不需要重启软件&#xff0c;能较好的定位问题。客户电脑上不需要…

上位机图像处理和嵌入式模块部署(树莓派4b和电源供给)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面&#xff0c;我们说过pc电脑和嵌入式设备&#xff0c;两者都可以实现相同的软件功能。但是和pc相比较&#xff0c;嵌入式设备不仅价格更便宜&a…

【Java】高效解决 非降序数组合并 两种方法

欢迎浏览高耳机的博客 希望我们彼此都有更好的收获 感谢三连支持&#xff01; oj&#xff1a;https://leetcode.cn/problems/merge-sorted-array/submissions/ 合并两个有序数组是个经典问题&#xff0c;它不仅在算法学习中频繁出现&#xff0c;也在实际开发中经常遇到。合并数…

「51媒体」邀请媒体参会报道和媒体发稿有啥不同

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体参会报道和媒体发稿是新闻报道的两种不同形式&#xff0c;它们的主要区别在于内容来源、报道方式和目的。 内容来源&#xff1a; 媒体参会报道&#xff1a;通常指的是记者或媒体代…