使用html2canvas.js实现页面截图并显示或上传

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

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

1、导入html2canvas.js

  这个不须要多说,能够从github上获取:https://github.com/niklasvh/html2canvasnode

  也能够直接导入连接: <script src="https://cdn.bootcss.com/html2canvas/0.5.0-beta4/html2canvas.js"></script> jquery

 

  使用起来也很是简单,具体的API能够去网上查找,生成png图片使用“image/png”便可。git

  其中$("#xxx")为你想要截取的div,外面能够经过jquery获取它,固然document获取也是能够的。github

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

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

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

2、svg没法截取的问题

  当咱们截取一个div时,若是这个div中存在svg标签,通常状况下是截取不到的,好比截取一个流程图,获得的是下面这个样子:数据库

 

  

  能够看到,流程图的线没有截取到,也就是svg没有截取到,这时的解决方法是把svg转换成canvas再进行截图便可,直接上代码。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,网上能够直接下载,也能够直接导入。

3、背景透明的问题

  这个其实很简单,由于它默认是透明的,html2canvas中有一个参数background就能够添加背景色,以下:

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

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

  若是须要截取的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); 

  最后能够在界面展现刚刚截取到的图片:

  

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

  如今获得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+`"> 。

  而后就能够看到界面上显示的图片了:

 

相关文章
相关标签/搜索