如题项目有需求将一个页面导出为pdf,然而页面中的图片却始终无法导出成功

一、导出的方法

查询了许多大佬的帖子,找到了如下导出的方法

const PdfDownload = function(domId) {var targetDom = $('#'+domId)//把需要导出的pdf内容clone一份,这样对它进行转换、微调等操作时才不会影响原来界面

var copyDom =targetDom.clone()//新的div宽高跟原来一样,高度设置成自适应,这样才能完整显示节点中的所有内容(比如说表格滚动条中的内容)

copyDom.width(targetDom.width() + 'px')

copyDom.height(targetDom.height()+200 + 'px')

$('body').append(copyDom)//ps:这里一定要先把copyDom append到body下,然后再进行后续的glyphicons2canvas处理,不然会导致图标为空

//svg2canvas(copyDom)

//loadImg(copyDom)

html2canvas(copyDom, {

onrendered:function(canvas) {var imgData = canvas.toDataURL('image/jpeg')var img = newImage()

img.src=imgData//根据图片的尺寸设置pdf的规格,要在图片加载成功时执行,之所以要*0.225是因为比例问题

img.onload = function() {//此处需要注意,pdf横置和竖置两个属性,需要根据宽高的比例来调整,不然会出现显示不完全的问题

if (this.width > this.height) {var doc = new jsPDF('l', 'mm', [this.width * 0.225, this.height * 0.225])

}else{var doc = new jsPDF('p', 'mm', [this.width * 0.225, this.height * 0.225])

}

doc.addImage(imgData,'jpeg', 0, 0, this.width * 0.225, this.height * 0.225)//根据下载保存成不同的文件名

doc.save('pdf_' + new Date().getTime() + '.pdf')

}//删除复制出来的div

copyDom.remove()

},

background:'#FFF',//这里给生成的图片默认背景,不然的话,如果你的html根节点没设置背景的话,会用黑色填充。

allowTaint: true //避免一些不识别的图片干扰,默认为false,遇到不识别的图片干扰则会停止处理html2canvas

})

}

二、初步测试的结果

有了上面的方法当然迫不及待的进行测试-- 测试导出页面如下

导出成功结果如下

这一测试发现并没有得到自己期望的结果,页面大致导出成功了,可是页面原本的头像图片怎么就没导出来呢?

三、使用f12查找原油

打开浏览器使用另一个用户进行测试发现… 该用户没有上传头像,我默认加载了一张本地的图片作为用户默认头像

而加载为默认图片的页面使用jsPdf将其进行导出,这个头像图片就可以成功被下载下来

于是做出如下推测…

经过这一测试初步断定是js 中同源策略所引起的跨域请求图片,所导致的jsPdf读取页面中图片失败的问题

四、方案一

到目前,问题虽然初步已锁定,但是还没有切实可行的解决方案,这咋办?

首先想到:就是把图片从服务器下载到本地

于是想到了使用nodeJS http+fs 从服务器将文件下载,然后将其写入到本地文件夹中

如参考 https://www.jianshu.com/p/28e3de79fd49

var http = require(''http'),fs = require('fs');

http.get(path,function(req,res){ //path为网络图片地址

var imgData ='';

req.setEncoding('binary');

req.on('data',function(chunk){

imgData += chunk

})

req.on('end',function(){

fs.writeFile(path,imgData,'binary',function(err){ //path为本地路径例如public/logo.png

if(err){console.log('保存出错!')}else{

console.log('保存成功!')

}

})

})

})

再重新 为节点添加一个img 标签,将其url指定为刚才下载的文件地址,在pdf 下载完成后再使用

如下方法将其删除掉 参考 https://blog.csdn.net/dongmelon/article/details/102456717

var fs = require('fs')/**

*

* @param {*} path 必传参数可以是文件夹可以是文件

* @param {*} reservePath 保存path目录 path值与reservePath值一样就保存*/

functiondelFile(path, reservePath) {if(fs.existsSync(path)) {if(fs.statSync(path).isDirectory()) {

let files=fs.readdirSync(path);

files.forEach((file, index)=>{

let currentPath= path + "/" +file;if(fs.statSync(currentPath).isDirectory()) {

delFile(currentPath, reservePath);

}else{

fs.unlinkSync(currentPath);

}

});if (path !=reservePath) {

fs.rmdirSync(path);

}

}else{

fs.unlinkSync(path);

}

}

}

后来经测试,很显然这个想法很幼稚(浏览器如何使用nodeJS?), 最终测试这种方法是不可行的!

五、方案二

/**

*

* 查询目标容器中images

* 使用nodejs进行图片下载到本地

* 增加一个image 使用本地src

* @param targetElem {Element object}*/

functionloadImg(targetElem){var svgElem = targetElem.find('img')

svgElem.each(function(index, node) {var parentNode =node.parentNode//通过构造函数来创建的 img 实例,在赋予 src 值后就会立刻下载图片,相比 createElement() 创建 省去了 append(),也就避免了文档冗余和污染

var Img = newImage(),

dataURL='';

Img.src=url;

Img.οnlοad=function(){ //要先确保图片完整获取到,这是个异步事件

var canvas = document.createElement("canvas"), //创建canvas元素

width=Img.width, //确保canvas的尺寸和图片一样

height=Img.height;

canvas.width=width;

canvas.height=height;

canvas.getContext("2d").drawImage(Img,0,0,width,height); //将图片绘制到canvas中

dataURL=canvas.toDataURL('image/jpeg'); //转换图片为dataURL

};

parentNode.appendChild(canvas)

})

}

后来又遇到了Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.

根据资料https://blog.csdn.net/u013040887/article/details/78986598 在方法中新增node.setAttribute('crossOrigin', 'anonymous'); 遗憾的是最后并未成功解决问题,依然需要重新寻找新的解决方案…

六、方案三

然后想到了使用XMLHttpRequest先把图片下载回来再重新为img 赋值

于是 增加如下方法使用 xmlHttpRequest进行图片下载

functiondownloadByXmlhttprequest(imgDom,cb){var xhr = newXMLHttpRequest()

xhr.onreadystatechange= function() {varblobif(xhr.readyState === 4){//使用URL.createObjectURL将Blob对象转换为可访问的url地址

var src =URL.createObjectURL(xhr.response)

console.log(src)

imgDom.src=src

cb(src)

}

}

xhr.open('GET',imgDom.src, true)//设置响应数据格式为Blob对象

xhr.responseType = 'blob'

//设置请求头

xhr.setRequestHeader('X-Requested-With', 'OpenAPIRequest')

xhr.send()

}

但是其中又遇到了请求未携带cookie而失败问题

最终经过如下多次测试,终于成功了

七、完整代码

最后完成这些操作的完整代码(这里我是写了一个外部js)如下

1、使用XMLHttpRequest进行图片二次下载

/**

* 使用XMLHttpRequest进行图片二次下载

* @param imgDom {Objec} target object

* @param cb{Object}success callback*/

functiondownloadByXmlhttprequest(imgDom,cb){var xhr = newXMLHttpRequest()

xhr.onreadystatechange= function() {if(xhr.readyState === 4){//使用URL.createObjectURL将Blob对象转换为可访问的url地址

var src =URL.createObjectURL(xhr.response)

imgDom.src=src

cb(src)

}

}

xhr.open('GET',imgDom.src, true)

xhr.withCredentials= true;//设置响应数据格式为Blob对象

xhr.responseType = 'blob'

//设置请求头

xhr.setRequestHeader('X-Requested-With', 'OpenAPIRequest')

xhr.send()

}

2、转换页面的图片

functionimgConvert(targetElem,cb){var svgElem = targetElem.find('img')

svgElem.each(function(index, node) {var parentNode =node.parentNode

downloadByXmlhttprequest(node,cb)

})

}

3、html2canvas执行下载

functionexecuteDown(copyDom){

html2canvas(copyDom, {

onrendered:function(canvas) {var imgData = canvas.toDataURL('image/jpeg')var img = newImage()

img.src=imgData//根据图片的尺寸设置pdf的规格,要在图片加载成功时执行,之所以要*0.225是因为比例问题

img.onload = function() {//此处需要注意,pdf横置和竖置两个属性,需要根据宽高的比例来调整,不然会出现显示不完全的问题

if (this.width > this.height) {var doc = new jsPDF('l', 'mm', [this.width * 0.225, this.height * 0.225])

}else{var doc = new jsPDF('p', 'mm', [this.width * 0.225, this.height * 0.225])

}

doc.addImage(imgData,'jpeg', 0, 0, this.width * 0.225, this.height * 0.225)//根据下载保存成不同的文件名

doc.save('pdf_' + new Date().getTime() + '.pdf')

}//删除复制出来的div

copyDom.remove()

},

background:'#FFF',//这里给生成的图片默认背景,不然的话,如果你的html根节点没设置背景的话,会用黑色填充。

allowTaint: true //避免一些不识别的图片干扰,默认为false,遇到不识别的图片干扰则会停止处理html2canvas

})

}

4、供外部调用的导出方法

const PdfDownload = function(domId) {var targetDom = $('#'+domId)//把需要导出的pdf内容clone一份,这样对它进行转换、微调等操作时才不会影响原来界面

var copyDom =targetDom.clone()//新的div宽高跟原来一样,高度设置成自适应,这样才能完整显示节点中的所有内容(比如说表格滚动条中的内容)

copyDom.width(targetDom.width() + 'px')

copyDom.height(targetDom.height()+200 + 'px')

$('body').append(copyDom)//ps:这里一定要先把copyDom append到body下,然后再进行后续的glyphicons2canvas处理,不然会导致图标为空

//svg2canvas(copyDom)

//loadImg(copyDom)

imgConvert(copyDom,function(res){

executeDown(copyDom)

})

}

export { PdfDownload }

最后这里使用到的 html2canvas-0.4.1 , jquery-2.1.4.min , jspdf.min 如下

插件网盘https://pan.baidu.com/s/1MMNOjmU8H3ebmWdB5nBzqw 提取码 jg7q

canvas节点无法导出图片_HTML转为PDF,图片导出失败的终极解决方案相关推荐

  1. CAD手机看图软件中怎么将CAD图纸转为PDF/图片格式?

    在使用CAD手机看图软件查看CAD图纸的时候,偶尔会遇到需要将CAD图纸转为PDF/图片格式的情况,这个时候该如何进行操作呢?下面给大家介绍一下在CAD手机看图软件浩辰CAD看图王中是如何进行操作的吧 ...

  2. 图片批量转为PDF怎么转?这些方法亲测实用

      你们平时在整理照片的时候,有把多张图片转为PDF文件的需求吗?我因为工作需要,会拍摄和存储很多照片,而且经常需要将这些照片归类,整合到一个PDF文件中.可能有的小伙伴还不知道多张图片转PDF怎么转 ...

  3. 利用python将图片格式转为PDF

    之前在朋友圈发现有人要将图片转为PDF,想着自己记录一下啊,不知道以后能不能用的上 需要的两个库(pillow,pypdf2) pip install xxx 就好了 代码部分 import os f ...

  4. html页面导出pdf截断问题,html2canvas 与 jspdf 相结合生成 pdf 内容被截断的终极解决方案...

    欢迎关注我的公众号 <人生代码> 我有一个大胆的想法,我要一直写到死,那一天我不写了,可能就死了.哈哈. 哈喽,大家好,我是你们的攻城狮,人贱人爱的 Ken,一个永远充满激情的人. 最近接 ...

  5. PDF文件怎么添加图片 如何编辑PDF图片

    在编辑文档的时候总会要插入一些图片内容,然后对图片进行一些简单的编辑和设置.像word.ppt这类常见的文档自然不必多少,大家也都知道怎样去操作.但是对PDF这种文档还是有很多人不熟悉的.那么在PDF ...

  6. 图片免费转pdf图片、图片免费转成word、图片免费转excel表格

    整个思想流程: ①.图片-->②.pdf图片-->③.word .excel: 这个流程是我所用方法基本转换的环节. 1.首先将jpg格式图片转换为pdf图片: 这里有许多工具可以使用: ...

  7. JAVA 把base64图片数据转为本地图片

    /*** 替换html中的base64图片数据为实际图片* @param html* @param fileRoot 本地路径* @param serRoot 服务器路径* @return*/publ ...

  8. python实现jpg、png等图片格式转为PDF

    import glob import os import fitzdef img2pdf_all2all(img_path,img_type,pdf_path):"""文 ...

  9. itext将html转为pdf,图片标签为base64的处理

    2019独角兽企业重金招聘Python工程师标准>>> 在http://my.oschina.net/yifanxiang/blog/678139中.修改了一下代码如下: /*** ...

  10. background 互联网图片_HTML页面插入图片,使用background还是img标签

    很多新手在刚开始学习HTML标签的时候,老师一定会教你 这种引入图片格式,第二天学习css的时候,老师又会教你给div等元素添加背景图片, div{background-image:url(xxx.p ...

最新文章

  1. 程序员面试时,不小心说了真话…...
  2. 博士笔记 | 深入理解深度学习语义分割
  3. MySQL模糊查询—like关键字
  4. 转jpg java源程序_将pdf文件转成图片并删除java源代码
  5. 给定数组,去掉0元素后将剩下的元素赋给新的数组
  6. 数据库路由中间件MyCat - 使用篇(1)
  7. (转)Managed DirectX +C# 开发(入门篇)(二)
  8. AndroidManifest.xml详解(service)
  9. 安装sun-java5-jdk 提示无法找到软件包sun-java5-jdk
  10. HTML框架分析及应用
  11. Micropython——L298N电机驱动模块
  12. 对计算机文化基础知识,计算机文化基础知识点总结(经典版)_考试专用
  13. 肥学献礼——自动写诗
  14. caffe框架deploy文件中
  15. hdmi接口线_视频接口与视频线详解!
  16. 数据库入口和密码:维普、万方和cnki(转)
  17. 解决JSONNull导致的JSONObject序列化问题
  18. 服务器硬盘常用的阵列方式有几种,三种常见磁盘阵列设置
  19. PPT和WORD转成PDF时图有黑底
  20. 深入剖析ReentrantLock公平锁与非公平锁源码实现

热门文章

  1. HBuilderX使用手机模拟器进行App开发详解【0基础讲解】
  2. DMP文件转CSV文件
  3. CGfsb [XCTF-PWN]CTF writeup系列2
  4. 弹箭三自由度弹道计算程序(c++ vs2017 )
  5. 北斗短报文的工作原理及作用
  6. 高端疫苗的新冠疫苗二期数据发表;药明生基新建工艺研发和商业化生产中心投运 | 医药健闻...
  7. PHP+实验室安全系统 毕业设计 -附源码191610
  8. 滴滴出行场景中语音识别模型的自学习平台化实践
  9. python二级考试操作题6答案_python二级考试试题6
  10. 安卓如何关闭软键盘?