最近写项目有用到html2canvas.js,可以实现页面的截图功能,但遭遇了许多的坑,特此写一篇随笔记录一下。

  在使用html2canvas时可能会遇到诸如只能截取可视化界面、截图没有背景色、svg标签无法截取等问题,下面详细的说明一下。

一、导入html2canvas.js

  这个不需要多说,可以从github上获取:https://github.com/niklasvh/html2canvas

  也可以直接导入链接: <script src="https://cdn.bootcss.com/html2canvas/0.5.0-beta4/html2canvas.js"></script>

  使用起来也非常简单,具体的API可以去网上查找,生成png图片使用“image/png”即可。

  其中$("#xxx")为你想要截取的div,外面可以通过jquery获取它,当然document获取也是可以的。

html2canvas($("#xxx"), {
onrendered: function (canvas) {
var url = canvas.toDataURL("image/png");
        window.location.href = url;
}
});

  其它类型的图片如jpg,为image/jpeg等等,可自行查询API。

  到这里其实简单的截图已经完成了,如果界面稍微复杂一点的话,可能就会出现各种坑,下面一个一个解决。

二、svg无法截取的问题

  当我们截取一个div时,如果这个div中存在svg标签,一般情况下是截取不到的,比如截取一个流程图,得到的是下面这个样子:

  

  可以看到,流程图的线没有截取到,也就是svg没有截取到,这时的解决方法是把svg转换成canvas再进行截图即可,直接上代码。

  这里的each循环是循环所有的svg标签,将它们全部转换为canvas

    if (typeof html2canvas !== 'undefined') {
//以下是对svg的处理
var nodesToRecover = [];
var nodesToRemove = [];
var svgElem = cloneDom.find('svg');
svgElem.each(function (index, node) {
var parentNode = node.parentNode;
var svg = node.outerHTML.trim(); var canvas = document.createElement('canvas');
canvas.width = 650;
canvas.height = 798;
canvg(canvas, svg);
if (node.style.position) {
canvas.style.position += node.style.position;
canvas.style.left += node.style.left;
canvas.style.top += node.style.top;
} nodesToRecover.push({
parent: parentNode,
child: node
});
parentNode.removeChild(node); nodesToRemove.push({
parent: parentNode,
child: canvas
}); parentNode.appendChild(canvas);
}); }

  这里需要用到canvg.js,以及它的依赖文件rgbcolor.js,网上可以直接下载,也可以直接导入。

三、背景透明的问题

  这个其实很简单,因为它默认是透明的,html2canvas中有一个参数background就可以添加背景色,如下:

html2canvas(cloneDom, {
onrendered: function(canvas) {
var url =canvas.toDataURL("image/png");
},
background:"#fafafa"
});

四、只能截取可视部分的问题

  如果需要截取的div超出了界面,可能会遇到截取不全的问题,如上图,只有一半的内容,这是因为看不到的部分被隐藏了,而html2canvas是无法截取隐藏的dom的。

  所以此时的解决办法是使用克隆,将需要截取的部分克隆一份放在页面底层,再使用html2canvas截取这个完整的div,截取完成后再remove这部分内容即可,完整代码如下:

function showQRCode() {
scrollTo(0, 0); //克隆节点,默认为false,即不复制方法属性,为true是全部复制。
var cloneDom = $("#d1").clone(true);
//设置克隆节点的z-index属性,只要比被克隆的节点层级低即可。
cloneDom.css({
"background-color": "#fafafa",
"position": "absolute",
"top": "0px",
"z-index": "-1",
"height": 798,
"width": 650
}); if (typeof html2canvas !== 'undefined') {
//以下是对svg的处理
var nodesToRecover = [];
var nodesToRemove = [];
var svgElem = cloneDom.find('svg');//divReport为需要截取成图片的dom的id
svgElem.each(function (index, node) {
var parentNode = node.parentNode;
var svg = node.outerHTML.trim(); var canvas = document.createElement('canvas');
canvas.width = 650;
canvas.height = 798;
canvg(canvas, svg);
if (node.style.position) {
canvas.style.position += node.style.position;
canvas.style.left += node.style.left;
canvas.style.top += node.style.top;
} nodesToRecover.push({
parent: parentNode,
child: node
});
parentNode.removeChild(node); nodesToRemove.push({
parent: parentNode,
child: canvas
}); parentNode.appendChild(canvas);
}); //将克隆节点动态追加到body后面。
$("body").append(cloneDom); html2canvas(cloneDom, {
onrendered: function(canvas) {
var url =canvas.toDataURL("image/png");
window.location.href = url ;
cloneDom.remove(); //清空克隆的内容
},
background:"#fafafa"
}); }
}

  这里外面首先将要截取的div克隆一份,并将z-index设置为最小,避免引起界面的不美观,然后是对svg进行的处理,上面已经分析过了,最后将克隆节点追加到body后面即可。

  在onrendered中,我们可以直接使用location.href跳转查看图片,可以进行保存操作,也可以将url写入img的src中显示在界面上,如 $('#imgId').attr('src',url);

  最后可以在界面展示刚刚截取到的图片:

  

五、上传图片保存到数据库,并在界面中获取该图片显示

  现在得到url了,需要上传到后端,并存到数据库中,再另一个展示的界面中加载该图片。我一般习惯于使用url来存储图片路径,而不是用blob存储。

  因为需要在另一个界面中获取图片,所以我把图片存在了与webapp同级的一个resource目录下,代码如下:

        //存储图片并返回图片路径
BASE64Decoder decoder = new BASE64Decoder();
byte[] b = decoder.decodeBuffer(product.getProPic().substring("data:image/png;base64,".length()));
ByteArrayInputStream bais = new ByteArrayInputStream(b);
BufferedImage bi1 = ImageIO.read(bais);
String url = "user_resource" + File.separator + "img" + File.separator + "product_"+UUID.randomUUID().toString().replace("-", "")+".png";
String totalUrl = System.getProperty("root") + url;
File w2 = new File(totalUrl);
ImageIO.write(bi1, "png", w2); product.setProPic(url); //将图片的相对路径存储到数据库中 int res = productMapper.insertSelective(product); //添加到数据库

  这里因为涉及到其它逻辑,所以只放一部分代码。

  这里使用的是BASE64Decoder来存储图片,我们获取到图片后,需要使用substring将“data:image/png;base64,”的内容截取掉,因为“,”后面才是图片的url, url.substring("data:image/png;base64,".length()) 。

  对于路径,上面代码中的url是我存储到数据库中的内容,而totalUrl就是实际进行ImageIO的write操作时存储的真实路径,getProperty()方法获取的项目的根目录,可以在web.xml中配置如下内容,然后 System.getProperty("root") 即可。

<!-- 配置系统获得项目根目录 -->
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>root</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.util.WebAppRootListener
</listener-class>
</listener>

  现在图片的url就存到数据库里了,而图片本身就存储在tomcat下该项目的这个目录下。

  

  最后外面在界面上获取,只需要在当前的url前面加上项目名即可 <img class="depot-img" src="<%=request.getContextPath()%>/`+e.proPic+`"> 。

  然后就可以看到界面上显示的图片了:

 

使用html2canvas.js实现页面截图并显示或上传的更多相关文章

  1. 使用JS实现页面中动态添加文件上传输入项

    1. 编写JSP <%@ page language="java" import="java.util.*" pageEncoding="UTF ...

  2. 如是使用JS实现页面内容随机显示

    之前有个客户咨询我,因为他们公司的业务员有多个人,但公司网站的联系方式板块里只够放一个人的信息,所以就想能不能实现这个联系方式信息随机显示,对于业务或客服人员来说也能做到分配均匀公平.本文我们将和大家 ...

  3. 利用来JS控制页面控件显示和隐藏有两种方法

    利用来JS控制页面控件显示和隐藏有两种方法,两种方法分别利用HTML的style中的两个属性,两种方法的不同之处在于控件隐藏后是否还在页面上占空位. 方法一:  1 2 document.getEle ...

  4. 利用html2canvas截图,得到base64上传ajax

    <script type="text/javascript" src="js/html2canvas.js"></script> //布 ...

  5. Jquery ajaxfileupload.js结合.ashx文件实现无刷新上传

    先上几张图更直观展示一下要实现的功能,本功能主要通过Jquery ajaxfileupload.js插件结合ajaxUpFile.ashx一般应用程序处理文件实现Ajax无刷新上传功能,结合NPOI2 ...

  6. JS兼容各个浏览器的本地图片上传即时预览效果

    JS兼容各个浏览器的本地图片上传即时预览效果 很早以前 在工作曾经碰到这么一个需求,当时也是纠结了很久,也是google了很久,没有碰到合适的demo,今天特意研究了下这方面的的问题,所以也就做了个简 ...

  7. Resumable.js – 基于 HTML5 File API 的文件上传

    Resumable.js 是一个 JavaScript 库,通过 HTML5 文件 API 提供,稳定和可恢复的批量上传功能.在上传大文件的时候通过每个文件分割成小块,每块在上传失败的时候,上传会不断 ...

  8. eclipse上传显示svn上传者名

    这里来记录下eclipse上传显示svn上传者名. 如图所示,修改即可.

  9. js 显示刚刚上传的图片 (onchange事件)

    <table> <tr width="100"> <td>上传商场图片:</td> <td> <input typ ...

随机推荐

  1. 分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!

    using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Caching; usi ...

  2. webpack4.0各个击破(10)—— Integration篇

    webpack作为前端最火的构建工具,是前端自动化工具链最重要的部分,使用门槛较高.本系列是笔者自己的学习记录,比较基础,希望通过问题 + 解决方式的模式,以前端构建中遇到的具体需求为出发点,学习we ...

  3. jquery 实现省市二级联动,附带完整的省市json数据 (粘贴即用)

    1.可以单独定义一个js,保存省市json数据. citydata = { "安徽": [ "合肥", "芜湖", "蚌埠&quo ...

  4. 【Docker】基础学习及在.Net Core应用

    一.Docker基础 Docker 是一个开源的应用容器引擎,基于 Go 语言 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发布到任何流行的 Linux 机器上 ...

  5. 如何解决升级到Dynamics 365后有很多的Sandbox的WorkerProcess并导致异常?

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复254或者20170505可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong. ...

  6. DVWA 黑客攻防演练(二)暴力破解 Brute Froce

    暴力破解,简称"爆破".不要以为没人会对一些小站爆破.实现上我以前用 wordpress 搭建一个博客开始就有人对我的站点进行爆破.这是装了 WordfenceWAF 插件后的统计 ...

  7. Docker 创建 Confluence6.12.2 中文版

    目录 目录 1.介绍 1.1.什么是Confluence? 2.Confluence的官网在哪里? 3.如何下载安装? 4.对 Confluence 进行配置 4.1.设置 Confluence 4. ...

  8. 使用 Browser-solidity 在 Go-Ethereum1.7.2 上进行简单的智能合约部署

    目录 目录 1.基本概念 1.1.什么是智能合约? 1.2.什么是Solidity? 1.2.1.Solidity的语言特性 1.3.什么是 Browser-solidity? 2.Browser-s ...

  9. 谈谈你对this对象的理解

    理解: 1.this是js 的一个关键字,随着函数的使用场合的不同,this 的值会发生变化. 2.一个总原则:即this指的是调用函数的那个对象. 3.一般情况下,this 是全局对象,可以作为方法 ...

  10. sed 查找文件的某一行内容

    1,查找文件text中第三行的内容 命令: sed -n '3p' text 2,查找文件text中第二行到第四行的内容 命令: sed -n '2,4p' text