zoukankan      html  css  js  c++  java
  • 使用html2canvas.js实现页面截图并显示或上传

      最近写项目有用到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+`"> 。

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

     

  • 相关阅读:
    1月5日学习记录||1月8日学习
    1.1学习记录|1.2日学习记录|1.3日
    RNA-seq数据为什么要去噪
    12.16日学习记录
    12.15学习记录
    transformer和bert简要学习
    关系抽取学习
    12.14周六学习记录
    12.5日学习记录
    12.4周三学习记录
  • 原文地址:https://www.cnblogs.com/adamjwh/p/10127666.html
Copyright © 2011-2022 走看看