网页转长图插件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

jsss-1 / test-html2canvas

推荐

网页转长图插件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;@PostConstructpublic 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")@ResponseBodypublic 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)@ResponseBodypublic 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

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

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

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

相关文章

超分辨率重建——CAMixerSR网络训练与推理测试(详细图文教程)

&#x1f4aa; 专业从事且热爱图像处理&#xff0c;图像处理专栏更新如下&#x1f447;&#xff1a; &#x1f4dd;《图像去噪》 &#x1f4dd;《超分辨率重建》 &#x1f4dd;《语义分割》 &#x1f4dd;《风格迁移》 &#x1f4dd;《目标检测》 &#x1f4dd;《暗光增强》 &a…

在做题中学习(56):二维前缀和模板

【模板】二维前缀和_牛客题霸_牛客网 (nowcoder.com) 理解题意&#xff1a; 要求的是(x1,y1) - (x2,y2)这段区间的和。 解法&#xff1a;二维前缀和 1. 和一维前缀和一样&#xff0c;需要有一个同等规模的dp数组&#xff0c;用来保存一段连续区域的和。 在二维dp中&#xff0…

客户案例:CACTER云网关为企业O365系统提供安全新护盾

一、客户背景 某智能驾驶企业是一家国际性的高科技创新型企业&#xff0c;其智能驾驶领域处于全球领先地位&#xff0c;专注于为广大客户提供个性化的智能驾驶解决方案&#xff0c;共建美好智能新时代。 使用产品&#xff1a;CACTER邮件安全云网关 二、痛点难点问题 根据…

最强特征点检测算法 DeDoDe v1/v2

论文地址v1:https://arxiv.org/pdf/2308.08479 论文地址v1:https://arxiv.org/pdf/2404.08928 代码地址:GitHub - Parskatt/DeDoDe: [3DV 2024 Oral] DeDoDe 🎶 Detect, Dont Describe --- Describe, Dont Detect, for Local Feature Matching 实测确实牛X! DeDoDeV1 关…

网安热议 | 中小企面临什么网络安全困扰?中小企网络安全是不是智商税?

近日&#xff0c;Coro 公司表示&#xff0c;许多中小型企业的 IT 人员被开发安全工作中多工具操作的复杂性和安全需求&#xff0c;压得“喘不过气”&#xff0c;导致其可能错过很多关键安全事件告警信息&#xff0c;从而将公司的网络安全置于危险之地。 研究机构采访了美国多行…

比大小(打擂台)(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>//声明比较大小函数max; int max(int a, int b);int main() {//初始化变量值&#xff1b;int i, n, m, a[10];//填充数组&#xff1b;printf("请输入10个数…

数据结构选择题(期末)

1.给定NN的二维数组A&#xff0c;则在不改变数组的前提下&#xff0c;查找最大元素的时间复杂度是&#xff08;A&#xff09;&#xff1a; A.O(N2) B.O(NlogN) C.O(N) D.O(N2logN) 两重循环即O(N2)的时间复杂度 2.与数据元素本身的形式、内容、相对位置、个数无关的是数据的…

MIT 6.5840(6.824) Lab1:MapReduce 设计实现

1 介绍 本次实验是实现一个简易版本的MapReduce&#xff0c;你需要实现一个工作程序&#xff08;worker process&#xff09;和一个调度程序&#xff08;coordinator process&#xff09;。工作程序用来调用Map和Reduce函数&#xff0c;并处理文件的读取和写入。调度程序用来协…

晶振在电子设备中的作用是什么?

在无源晶振电路中&#xff0c;并联电阻起着至关重要的作用。无源晶振本身不能自行产生振荡&#xff0c;因此需要借助外部电路来实现。并联在晶振两端的电阻&#xff0c;通常称为负载电阻&#xff0c;对电路的稳定性和振荡性能有着重要影响。 晶振电路的核心是皮尔斯振荡器&…

mysql根据字段值关联查不同表

mysql根据字段值关联查不同表&#xff1a; 实现&#xff1a; 使用left join 结合case when 判断直接取值&#xff1a; select mp.member_id ,mp.store_id, case mp.store_type when 1 then bs.store_namewhen 2 then sc.store_namewhen 3 then be.store_name end as store_na…

string类篇超超超详解,40余个成员函数详细解释(图文)!看完包会!!

本篇目标 constructoroperatorElements accessIteratorsCapacityModifiersString operationsmember contants其他函数 一、constructor(对象的创建) void StrTest1() {string s1;//直接构造cout << s1 << endl;//string里内置了流插入、流提取的函数重载&#xf…

Naive RAG 、Advanced RAG 和 Modular RAG 简介

简介&#xff1a; RAG&#xff08;Retrieval-Augmented Generation&#xff09;系统是一种结合了检索&#xff08;Retrieval&#xff09;和生成&#xff08;Generation&#xff09;的机制&#xff0c;用于提高大型语言模型&#xff08;LLMs&#xff09;在特定任务上的表现。随…

深入解析RedisJSON:在Redis中直接处理JSON数据

码到三十五 &#xff1a; 个人主页 JSON已经成为现代应用程序之间数据传输的通用格式。然而&#xff0c;传统的关系型数据库在处理JSON数据时可能会遇到性能瓶颈。为了解决这一问题&#xff0c;Redis推出了RedisJSON模块&#xff0c;它允许开发者在Redis数据库中直接存储、查询…

产品推荐 | 基于 AMD Virtex UltraScale FPGA VCU1287 的特性描述套件

01 产品概述 VCU1287 功能描述套件可为您提供描述和评估 Virtex™ UltraScale™ XCVU095-FFVB2104E FPGA 上可用 32 GTH (16Gbps) 和 32 GTY (30Gbps) 收发器所需的一切功能。每个 GTH 与 GTY Quad 及其相关参考时钟均从 FPGA 路由至 SMA 及 Samtec BullsEye 连接器。 Bulls…

好题总结汇总

好题总结汇总 总结一些做完很有收获的题。 一、经典问题 DP的结合 1、题意&#xff1a; 给定 n n n 种颜色的球的数量 a 1 , a 2 , . . . , a n a_1, a_2, ..., a_n a1​,a2​,...,an​&#xff0c;选出一些不同种类的球(也就是在n种球中选球的任意情况)&#xff0c;将球…

TCP的滑动窗口机制和流量控制

目录 滑动窗口 流量控制 拥塞控制 滑动窗口 TCP除了保证可靠性之外&#xff0c;也希望能够尽可能高效的完成数据传输。滑动窗口就是一种提高效率的机制。以下是不引入滑动窗口的数据传输过程&#xff1a; 可以看到&#xff0c;主机A这边每次收到一个ACK才发送下一个数据。这…

为什么cca门限和tx 功率有关系

Cca是用来决定信道是否繁忙&#xff0c;好像只和收有关。 但是为什么和tx有关。 设想一下这个网路布局。 如果某个STA在决定是否发送的时候&#xff0c;是否不能只看收到的干扰多大&#xff0c;还应该“冒险”一下&#xff0c;如果自己的功率足够&#xff0c;那么就可以扛住干…

MyBatis的注解实现复杂映射开发

xml 配置方式实现复杂映射回顾 ​ 实现复杂映射我们之前可以在映射文件中通过配置来实现&#xff0c;使用注解开发后&#xff0c;我们可以通过 Results 注解&#xff0c;Result 注解&#xff0c;One 注解和 Many 注解组合完成复杂关系的配置。 注解说明Results代替的是标签 …

【csv-parse】使用parse方法的时候来转换为csv字符串时,会导致输出有乱码

&#x1f601; 作者简介&#xff1a;一名大四的学生&#xff0c;致力学习前端开发技术 ⭐️个人主页&#xff1a;夜宵饽饽的主页 ❔ 系列专栏&#xff1a;前端bug记录 &#x1f450;学习格言&#xff1a;成功不是终点&#xff0c;失败也并非末日&#xff0c;最重要的是继续前进…

Vue3组件库开发项目实战——02项目搭建(配置Eslint/Prettier/Sass/Tailwind CSS/VitePress/Vitest)

摘要&#xff1a;在现代前端开发中&#xff0c;构建一个高效、可维护且易于协作的开发环境至关重要。特别是在开发Vue3组件库时&#xff0c;我们需要确保代码的质量、一致性和文档的完整性。本文将带你从0搭建vue3组件库开发环境&#xff0c;以下是配置代码规范、格式化、CSS样…