当前位置: 首页 > news >正文

前端生成pdf之html2canvas+jsPDF,以及解决图片不显示bug

前端如何生成pdf

开发背景: 需要给页面中相应的内容生成pdf,查找文档后发现要用到两个插件。html2canvas 以及 jsPDF

  • html2canvas 给dom结构转化为canvas,然后生成各种类型图片
  • jsPDF 把canvas 生成的图片url 转化为pdf
// 插入图片
pdf.addImage(image, format, x, y, width, height, alias, compression, rotation)
// 保存为pdf
pdf.save("example.pdf");

参数

  1. image:表示要插入的图片资源,可以是图片文件的路径或者base64编码字符串。
  2. format:表示要插入的图片格式,包括:‘JPEG’, ‘PNG’, ‘GIF’, ‘BMP’, ‘TIFF’, ‘RAW’, ‘JPEG2000’。
  3. x:图片在PDF中的x轴坐标,单位为pt(点)。
  4. y:图片在PDF中的y轴坐标,单位为pt(点)。
  5. width:图片在PDF中的宽度,单位为pt(点)。
  6. height:图片在PDF中的高度,单位为pt(点)。
  7. alias(可选):指定图片资源的别名。
  8. compression(可选):指定图片的压缩质量,取值为0-1之间的浮点数。
  9. rotation(可选):指定图片的旋转角度,取值范围为0-360之间的整数。

下面是dom转化为pdf 的基本代码

import html2canvas from 'html2canvas';
import jsPdf from 'jspdf';function printPDF () {const domElement = document.getElementById('your-id');html2canvas(domElement, {onclone: (document) => {document.getElementById('print-button').style.visibility = 'hidden';}}).then((canvas) => {const img = canvas.toDataURL('image/png');const pdf = new jsPdf();pdf.addImage(imgData, 'JPEG', 0, 0, width, height);pdf.save('your-filename.pdf');
})

需要特别注意一下 html2canvas onclone 方法。它是当DOM被克隆后进行渲染时的回调函数,可用于修改将要渲染的内容,而不会影响原始DOM。当你需要在生成快照前操作 DOM(例如隐藏打印按钮)时,会非常有用。

难点突破

1. 使用html2canvas转为图片遇到跨域问题

跨域图片不会生成:由于跨域的问题(比如图片在第三方存放),导致图片不会被绘制,需要多方配置;
1. html2canvas的配置项中配置 allowTaint:trueuseCORS:true(二者不可共同使用)
2. img标签增加 crossOrigin='anonymous'
3. 图片服务器配置Access-Control-Allow-Origin 或使用代理
其中第三步是最重要的,不设置则前两步设置了也无效。
如果后端不能改图片服务器,咱们前端也能设置图片代理,例如nginx server配置

	location /img {proxy_pass 服务器真正地址;}

2. html2canvas转化的图片,ios设备长按可以保存,Android设备长按无法保存

  1. 原因分析:转换后使用canvas.toDataURL拿到的是base64的图片,此图片可以直接展示在网页上,但是在Android设备上长按此图片无法保存,ios设备可以长按保存;原因是Android无法长按保存base64的图片,
  2. 解决办法:可以考虑将图片先上传到服务器拿到url再展示

3. safir长按保存不了图片

使用-webkit-touch-callout:default不规范的属性,iOS 2.0及更高版本的Safari浏览器可用

4. 生成的图片中若包含二维码,微信长按图片偶现无法识别

不使用路由切换,使用window.location.href直接跳转刷新页面

5. 生成的PDF超出一页后分页问题

  1. 需要计算图片的宽高,一页展示多少

看详细代码

printPDF(id, name){const domElement = document.getElementById(id);html2canvas(domElement, {allowTaint: false,useCORS: true,   // 用于解决图片跨域onclone: (document) => {document.getElementById('print-button').style.visibility = 'hidden';}}).then((canvas) => {const fileName = name + (new Date()).toLocaleString() + '.pdf'var pdf = new jsPdf('p', 'mm', 'a4'); // A4纸,纵向var ctx = canvas.getContext('2d');var a4w = 190; var a4h = 277; // A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277var imgHeight = Math.floor(a4h * canvas.width / a4w); // 按A4显示比例换算一页图像的像素高度var renderedHeight = 0;while (renderedHeight < canvas.height) {var page = document.createElement('canvas');page.width = canvas.width;page.height = Math.min(imgHeight, canvas.height - renderedHeight);// 可能内容不足一页            // 用getImageData剪裁指定区域,并画到前面创建的canvas对象中page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0);pdf.addImage(page.toDataURL('image/jpeg', 1.0), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width)); // 添加图像到页面,保留10mm边距renderedHeight += imgHeight;if (renderedHeight < canvas.height) {pdf.addPage();// 如果后面还有内容,添加一个空页}// delete page;}// 保存文件pdf.save(fileName);})}

相关文章:

前端生成pdf之html2canvas+jsPDF,以及解决图片不显示bug

前端如何生成pdf 开发背景&#xff1a; 需要给页面中相应的内容生成pdf&#xff0c;查找文档后发现要用到两个插件。html2canvas 以及 jsPDF html2canvas 给dom结构转化为canvas&#xff0c;然后生成各种类型图片jsPDF 把canvas 生成的图片url 转化为pdf // 插入图片 pdf.addI…...

PHP常用符号和函数

// 单行注解 /* */ 多行注解 引号的使用 ’ ’ 单引号,没有任何意义,不经任何处理直接拿过来; ” “双引号,php动态处理然后输出,一般用于变量. 变量形态: 一种是True 即 真的; 另一种是False 即假的 常见变量形态: string 字串(数字\汉字\等等) integer 整数(1、2、…...

C#,入门教程(12)——数组及数组使用的基础知识

上一篇&#xff1a; C#&#xff0c;入门教程(11)——枚举&#xff08;Enum&#xff09;的基础知识和高级应用https://blog.csdn.net/beijinghorn/article/details/123917587 数组是一种数据集合&#xff0c;是一组完全相同的、按顺序存放的数据。 需要记住数组的几个特征&…...

C语言中的副作用、序列点以及复杂表达式的求值顺序

C语言中复杂表达式的求值顺序 num (5 2) * (9 * 6);如果我问你&#xff1a;上面的c程序在执行的时候到底是先算&#xff08;5 2&#xff09;还是&#xff08;9 * 6&#xff09;&#xff1f;你会怎么回答&#xff1f; 无非就两种&#xff1a;先算&#xff08;5 2&#xff…...

C++学习笔记——队列模拟

目录 一、模拟队列 二、模拟队列的知识点 三、队列 3.1入队操作 3.2出队操作 3.3访问队首元素 3.4访问队尾元素 3.5判断队列是否为空 3.6获取队列的大小 四、实现队列的基本功能 一、模拟队列 当涉及到数据存储和处理时&#xff0c;队列是一种常见的数据结构&#x…...

jvm垃圾回收相关的算法

什么是垃圾 JVM主要通过以下几种方式来判断对象是否需要回收&#xff1a; 引用计数法&#xff1a;JVM通过引用计数器来判断对象的引用数量&#xff0c;当引用数量为0时&#xff0c;表示对象可以被回收。 可达性分析算法&#xff1a;JVM通过根对象&#xff08;如栈中的引用、静…...

每日coding

2085、统计出现过一次的公共字符串 给你两个字符串数组 words1 和 words2 &#xff0c;请你返回在两个字符串数组中 都恰好出现一次 的字符串的数目。 示例 1&#xff1a; 输入&#xff1a;words1 ["leetcode","is","amazing","as"…...

软件工程_复习

软件工程 软件危机(1968 60年代) 产生软件危机的原因: 一方面与软件本身的特点有关,另一方面也和软件开发和维护的方法不正确有关。 与软件本身特点有关: 1.软件不同于硬件,软件是计算机系统中的逻辑部件,缺乏“可见性”,管理和控制软件开发过程相当困难 2.软件在运行过…...

07GoF之三种工厂模式

GoF&#xff08;Gang of Four&#xff09;:四人组,《Design Patterns: Elements of Reusable Object-Oriented Software》&#xff08;《设计模式》)的作者,设计了23种设计模式.但时代发展,还有其它的设计模式&#xff0c;比如&#xff1a;JavaEE的设计模式&#xff08;DAO模式…...

JAVA面试部分——后端-线程前篇

3.1 线程和进程 在计算机科学中&#xff0c;进程和线程是操作系统管理资源的两种不同方式。 进程&#xff08;Process&#xff09;&#xff1a;是程序在计算机上的一次执行活动。每个进程都有自己的内存空间&#xff0c;包括代码、数据和系统资源。一个进程可以包含多个线程。…...

【小沐学C++】C++ 实现鼠标键盘钩子HOOK

文章目录 1、简介2、相关函数2.1 SetWindowsHookEx2.2 UnhookWindowsHookEx2.3 CallNextHookEx 3、相关结构体3.1 KBDLLHOOKSTRUCT3.2 MSLLHOOKSTRUCT 4、挂钩过程5、代码测试5.1 代码1 结语 1、简介 https://learn.microsoft.com/zh-cn/windows/win32/winmsg/about-hooks 挂…...

【pycharm】常见问题与解决

记录一些Pycharm中经常遇到的问题 1. “Open file or Project” always in loading state (hang) a) 老版本 (2021年左右) since build 211.6693.14, it is possible to use a native file chooser on Windows. The feature is experimental; to enable it, add the followi…...

flask web学习之表单(一)

文章目录 一、使用Flask-WTF处理表单1.1 安装Flask-WTF库1.2 定义WTForms表单类常用的WTForm字段实例化字段类常用参数常用的WTForm验证器 1.3 输出HTML代码使用render_kw属性在调用字段时传入 1.4 在模板中渲染表单 在web程序中&#xff0c;表单是用户交互最常见的方式之一。用…...

@ControllerAdvice 使用场景

ControllerAdvice 是Spring 框架中的注解&#xff0c;多用在Spring MVC应用程序中。 使用场景1&#xff1a;处理异常 # 示例1 import org.apache.ibatis.javassist.NotFoundException; import org.springframework.http.HttpStatus; import org.springframework.http.Respons…...

二极管选型怎么选?常用参数要熟练~

同学们大家好&#xff0c;今天我们继续学习杨欣的《电子设计从零开始》&#xff0c;这本书从基本原理出发&#xff0c;知识点遍及无线电通讯、仪器设计、三极管电路、集成电路、传感器、数字电路基础、单片机及应用实例&#xff0c;可以说是全面系统地介绍了电子设计所需的知识…...

【小白专用】C#关于角色权限系统

&#xff08;C#&#xff09;用户、角色、权限 https://www.cnblogs.com/huangwen/articles/638050.html 权限管理系统——数据库的设计&#xff08;一&#xff09; https://www.cnblogs.com/cmsdn/p/3371576.html 权限管理系统——菜单模块的实现&#xff08;二&#xff09; …...

代码随想录算法训练营

一刷打卡记录&#xff1a; 日期打卡2023/10/25 day01二分查找有点转不过弯&#xff0c;快慢指针能理解&#xff0c;自己写也可能写不出来&#xff0c;但是能记住了&#xff0c;能看懂&#xff0c;还有其他解法待补充看完&#xff0c;花了挺长时间的2023/10/26 day02还好&#…...

统计学-R语言-3

文章目录 前言给直方图增加正态曲线的不恰当之处直方图与条形图的区别核密度图时间序列图洛伦茨曲线计算绘制洛伦茨曲线所需的各百分比数值绘制洛伦茨曲线 练习 前言 本篇文章是介绍对数据的部分图形可视化的图型展现。 给直方图增加正态曲线的不恰当之处 需要注意的是&#…...

spring动态控制定时任务

在spring框架中&#xff0c;对于简单的定时任务&#xff0c;可以使用 Scheduled 注解实现&#xff0c;在实际项目中&#xff0c;经常需要动态的控制定时任务&#xff0c;比如通过接口增加、启动、停止、删除定时任务&#xff0c;动态的改变定时任务的执行时间等。 我们可以通过…...

3. Mybatis 中SQL 执行原理

2. Mybatis 中SQL 执行原理 这里有两种方式&#xff0c;一种为常用的 Spring 依赖注入 Mapper 的方式。另一种为直接使用 SqlSessionTemplate 执行 Sql 的方式。 Spring 依赖注入 Mapper 的方式 Mapper 接口注入 SpringIOC 容器 Spring 容器在扫描 BeanDefinition 阶段会扫…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

visual studio 2022更改主题为深色

visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中&#xff0c;选择 环境 -> 常规 &#xff0c;将其中的颜色主题改成深色 点击确定&#xff0c;更改完成...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...