纯js实现html转pdf

项目开发中遇到了一个变态需求,需要把一整个页面导出为pdf格式,而且要保留页面上的所有的表格、svg图片和样式。

简而言之,就是希望像截图一样,把整个页面截下来,然后保存成pdf。

咋不上天呢……

查了一下,能够实现html转pdf的方法还是挺多的,大概有以下几种:

1、大部分浏览器就有这个功能。然而我们客户要的可不是这个,人家要的是能够在系统中主动触发的导出为pdf功能,所以这种方案pass。

2、利用第三方工具。我找到了一种利用wkhtmltopdf这种工具来导出的方案,自己在我们的项目中试了一下,效果不好,而且对svg图片的支持也不行。pass。

3、还有一种是利用iText类后台生成java文件。但因为需要导出的这个页面是动态页面,而且直接把页面传给后台会丢失大量样式,所以还是pass。

最后没什么好的办法,只能退而求其次,想着要不先把html页面转成图片,再把图片导出为pdf。因为要支持用户导出下载,而且要保留样式,所以最好是纯js前端实现。

html转canvas的话,就用html2canvas这个js,这个网上介绍比较多了,这里就不废话了。

比较麻烦的是svg图片,直接用html2canvas无法把svg标签的内容转成canvas,最后查了一圈资料后,锁定了canvg这个js。canvg是谷歌的一个插件,可以将svg标签内容转成canvas。具体到我们的项目,还有一个难点,就是如何把glyphicons这种字体图标也转成canvas,因为在不同浏览器下对这种字体图标的支持是完全不一样的。最后找到的方法是用char code来替换这些字体图标,重新绘制成canvas。由canvas生成图片不用废话。由图片生成pdf用jsPDF实现。 折腾了大半天,总算把整个流程打通了,接下来一步一步贴上代码。

第一步:把对应dom节点里所有的svg元素替换成canvas

 1 svg2canvas: function(targetElem) {
 2   var svgElem = targetElem.find('svg');
 3   svgElem.each(function(index, node) {
 4     var parentNode = node.parentNode;
 5     //由于现在的IE不支持直接对svg标签node取内容,所以需要在当前标签外面套一层div,通过外层div的innerHTML属性来获取
 6     var tempNode = document.createElement('div');
 7     tempNode.appendChild(node);
 8     var svg = tempNode.innerHTML;
 9     var canvas = document.createElement('canvas');
10     //转换
11     canvg(canvas, svg);
12     parentNode.appendChild(canvas);
13   });
14 }

第二步:把glyphicons字体转成canvas。如果项目中没有用到glyphicons字体图标,可忽略这一步

 1 glyphicons2canvas: function(targetElem, fontClassName, fontFamilyName) {
 2   var iconElems = targetElem.find('.' + fontClassName);
 3   iconElems.each(function(index, inconNode) {
 4     var fontSize = $(inconNode).css("font-size");
 5     var iconColor = $(inconNode).css("color");
 6     var styleContent = $(inconNode).attr('style');
 7     //去掉"px"
 8     fontSize = fontSize.replace("px", "");
 9     var charCode = getCharCodeByGlyphiconsName(iconName);
10     var myCanvas = document.createElement('canvas');
11     //把canva宽高各增加2是为了显示图标完整
12     myCanvas.width = parseInt(fontSize) + 2;
13     myCanvas.height = parseInt(fontSize) + 2;
14     myCanvas.style = styleContent;
15     var ctx = myCanvas.getContext('2d');
16     //设置绘图内容的颜色
17     ctx.fillStyle = iconColor;
18     //设置绘图的字体大小以及font-family的名字
19     ctx.font = fontSize + 'px ' + fontFamilyName;
20     ctx.fillText(String.fromCharCode(charCode), 1, parseInt(fontSize) + 1);
21     $(inconNode).replaceWith(myCanvas);
22   });
23 }
24 //根据glyphicons/glyphicon图标的类名获取到对应的char code
25 getCharCodeByGlyphiconsName: function(iconName) {
26   switch (iconName) {
27   case("glyphicons-resize-full"):
28     return "0xE216";
29   case ("glyphicons-chevron-left"):
30     return "0xE225";
31   default:
32     return "";
33   }
34 }

第三步:html转canvas转图片再转pdf

 1 html2canvas($("#myExportArea"), {
 2   onrendered: function(canvas) {
 3     var imgData = canvas.toDataURL('image/jpeg');
 4     var img = new Image();
 5     img.src = imgData;
 6     //根据图片的尺寸设置pdf的规格,要在图片加载成功时执行,之所以要*0.225是因为比例问题
 7     img.onload = function() {
 8       //此处需要注意,pdf横置和竖置两个属性,需要根据宽高的比例来调整,不然会出现显示不完全的问题
 9       if (this.width > this.height) {
10         var doc = new jsPDF('l', 'mm', [this.width * 0.225, this.height * 0.225]);
11       } else {
12         var doc = new jsPDF('p', 'mm', [this.width * 0.225, this.height * 0.225]);
13       }
14       doc.addImage(imgData, 'jpeg', 0, 0, this.width * 0.225, this.height * 0.225);
15       //根据下载保存成不同的文件名
16       doc.save('report_pdf_' + new Date().getTime() + '.pdf');
17     }
18   },
19   background: "#fff",
20   //这里给生成的图片默认背景,不然的话,如果你的html根节点没设置背景的话,会用黑色填充。
21   allowTaint: true //避免一些不识别的图片干扰,默认为false,遇到不识别的图片干扰则会停止处理html2canvas
22 });

虽然最后勉强完成了客户的要求,但是生成的pdf效果明显不如正常截图来的清晰……水平所限,暂时只能想到这种方法,如果大家有更好的办法,欢迎指点。

一个简单的demo:https://github.com/SuperNaturalGit/HtmlToPdf

使用方法:

使用Git克隆项目到本地:git clone https://github.com/SuperNaturalGit/HtmlToPdf.git

使用chrome浏览器打开index.html即可。其他浏览器的兼容性没测试。

如果不用git,直接把几个文件全部copy到本地,只要相对路径没问题,也可以运行的。

ps:评论里冷秋月同学对导出流程做了改良,可以解决闪烁以及背景的问题,大家可以参考。

转载于:https://www.cnblogs.com/skyInk/p/6401563.html

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

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

相关文章

java 判断是linux系统_java判断是window系统还是Linux系统,并获取其IP地址及文件上传 | 学步园...

这是upload类的方法:public class Upload {public static String upload(FormFile formfile,String dirPath,int port){String savePath"";String ip"";try{String filename formfile.getFileName().trim(); // 文件名if (!"".equal…

物联网中的推荐系统

来源:北京物联网智能技术应用协会作者 | Alexander Felfernig, Seda Polat Erdeniz编译 | CDA数据科学研究院Recommender systems in the Internet of Things1、背景介绍物联网是一种联网的基础架构,是物联网、互联网和语义学领域之间融合的结果&#xf…

pwm控制的基本原理_单片机PWM控制基本原理详解~

PWM是Pulse Width Modulation的缩写,它的中文名字是脉冲宽度调制,一种说法是它利用微处理器的数字输出来对模拟电路进行控制的一种有效的技术,其实就是使用数字信号达到一个模拟信号的效果。这是个什么概念呢?我们一步步来介绍。首…

关上Deepfake的潘多拉魔盒,RealAI推出深度伪造视频检测工具

诞生之初,Deepfake是一项有趣的图像处理技术,仅仅带来搞笑和娱乐视频,但殊不知,潘多拉魔盒就此被打开,催生出色情黑产、恶搞政客“操纵”民意,Deepfake正逐步进化为一种新型“病毒”,人类伦理道…

java 解析 csv_在Java中将数据从CSV解析到数组

我正在尝试将CS​​V文件导入到可以在Java程序中使用的数组中. CSV文件已成功导入自身,输出显示在终端上,但它会引发错误:Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1at CompareCSV.main(CompareCSV.java:19)在末尾.另外,当…

python画国际象棋_python图形工具turtle绘制国际象棋棋盘

本文实例为大家分享了python图形工具turtle绘制国际象棋棋盘的具体代码,供大家参考,具体内容如下#编写程序绘制一个国际象棋的棋盘import turtleturtle.speed(30)turtle.penup()off Truefor y in range(-40, 30 1, 10):for x in range(-40, 30 1, 10)…

谷歌地图的全球森林监察系统,揭秘中国雾霾的惊天秘密!

来源:老牛时评谷歌公司最近推出的全新交互式地图——“全球森林监察”它可以实时显示全球森林的覆盖情况。该幅地图的数据来源有多个,其中包括了NASA的森林面积覆盖率的分析数据。于是我们选取了中国及中国周边的部分,看完后的感受只能是比悲…

dbref java_查询mongodb dbref内部字段

我需要隐藏其isActive标志设置为false的所有用户相关数据 . 有许多集合我使用了DBRef类型的用户集合(大约14个集合),每个集合包含超过1000万条记录 .让我借助例子更恰当地解释一下 .假设我有两个集合:用户联系用户集包含以下字段:名字(字符串…

qt显示rgba8888 如何改 frame_Qt开源作品17-IP地址输入控件

一、前言这个IP地址输入框控件,估计写烂了,网上随便一搜索,保证一大堆,估计也是因为这个控件太容易了,非常适合新手练手,一般的思路都是用4个qlineedit控件拼起来,然后每个输入框设置正则表达式…

web.xml文件头出错

原先将web.xml文件头设置为如下格式 <?xml version"1.0" encoding"UTF-8"?><web-app version"3.1" xmlns"http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:sche…

Nature子刊超越诺贝尔经典理论:神经科学研究路漫漫...

科学家正在观察一台用于记录小鼠脑细胞活动的双光子显微镜。图片来源&#xff1a;艾伦研究所来源&#xff1a;中国生物技术网 北京时间12月17日&#xff0c;发表在《Nature Neuroscience》上一项针对小鼠视觉系统中近6万个神经元活动的新研究显示&#xff0c;要想了解大脑如何计…

java 替换多个字符串_Java一次(或以最有效的方式)替换字符串中的多个不同子字符串...

小编典典如果你要处理的字符串很长&#xff0c;或者你要处理许多字符串&#xff0c;那么使用java.util.regex.Matcher可能是值得的(这需要花很长时间进行编译&#xff0c;因此效率不高) (如果你的输入很小或搜索模式经常更改)。以下是一个完整的示例&#xff0c;基于从地图中获…

python输出子列表_python利用递归函数输出嵌套列表的每个元素

递归函数实现&#xff1a;defgetitem(l):for item inl:ifisinstance(item,list):getitem(item)else:print(item)getitem(l)输出:12345678910变式1&#xff1a;遇到类表就缩进一次&#xff1a;def getitem(l,level0):for item in l:if isinstance(item,list):getitem(item,level…

偏见与人类大脑结构有关

来源&#xff1a;科技日报偏见是如何产生的&#xff1f;据英国《自然神经科学》16日发表的一项脑科学研究发现&#xff0c;内侧前额叶皮质后部&#xff08;pMFC&#xff09;会促进人类产生确认偏误。具体而言&#xff0c;对于那些不会让自己更加相信已有观念的意见&#xff0c;…

java 设计方法_java 中如何处理设计一个方法

java 中我们很常见的设计 API 的例子是对一个对象进行增, 删, 查,改.比如Object addObject(Object obj);Object delObject(Object obj);Object modifyObject(Object obj);成功返回 obj, 不成功(参数不合法,或已经存在, 或不存在)抛出异常还是int addObject(Object obj);int del…

python获取mac窗口坐标_[代码全屏查看]-Python3根据IP地址获取MAC地址

[1].[代码] [Python]代码#!/usr/bin/env python3# -*- coding: utf-8 -*-import osimport platformimport reclass IP2MAC:def __init__(self):self.patt_mac re.compile(([a-f0-9]{2}[-:]){5}[a-f0-9]{2}, re.I)def getMac(self, ip):sysstr platform.system()if sysstr Wi…

PLECS软件学习使用(一)简单的RLC电路搭建

PLECS软件学习使用&#xff08;一&#xff09;简单的RLC电路搭建 1相关操作总结&#xff1a; 旋转&#xff1a;CtrlR 翻转&#xff1a;CtrlF 从连线中引出线&#xff1a;Ctrl鼠标左键 设置元件参数&#xff1a;双击元件&#xff0c;进行设置&#xff0c;若要显示参数&#xff0…

《自然》公布年度十大杰出论文

来源&#xff1a;科技日报 英国《自然》杂志网站日前公布了2019年十大杰出论文&#xff0c;接近室温的超导体、精确编辑基因技术、海王星新卫星等纷纷入选。其中&#xff0c;中国研究占到两席&#xff0c;分别是来自复旦大学的亨廷顿舞蹈症新疗法&#xff0c;与中科院上海有机化…

python 加密方法总结

MD5 def md5(str):import hashlibm hashlib.md5()m.update(str)return m.hexdigest() base64 import base64s 我是字符串a base64.b64encode(s)print a print base64.b64decode(a)输出结果&#xff1a; ztLKx9fWt/u0rg 我是字符串 转载于:https://www.cnblogs.com/superxuez…

中国电子信息工程科技发展十大趋势(2019)发布

来源&#xff1a;新浪科技17日&#xff0c;中国工程院信息与电子学部、中国信息与电子工程科技发展战略研究中心在中国工程院召开发布会&#xff0c;发布“中国电子信息工程科技发展十大趋势&#xff08;2019&#xff09;”。中国工程院副院长陈左宁院士表示&#xff0c;中国工…