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


Posted in HTML / CSS onDecember 18, 2018

最近写项目有用到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标签,一般情况下是截取不到的,比如截取一个流程图,得到的是下面这个样子:

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

可以看到,流程图的线没有截取到,也就是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);

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

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

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

现在得到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下该项目的这个目录下。

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

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

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

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

HTML / CSS 相关文章推荐
CSS3实现头像旋转效果
Mar 13 HTML / CSS
巧用 CSS3的webkit-box-reflect 倒影实现各类动效
Mar 05 HTML / CSS
HTML5 使用 sessionStorage 进行页面传值的方法
Jul 02 HTML / CSS
让IE下支持Html5的placeholder属性的插件
Sep 02 HTML / CSS
HTML5新增加标签和功能概述
Sep 05 HTML / CSS
基于HTML5陀螺仪实现ofo首页眼睛移动效果的示例
Jul 31 HTML / CSS
HTML5视频播放插件 video.js介绍
Sep 29 HTML / CSS
canvas 基础之图像处理的使用
Apr 10 HTML / CSS
html5简介及新增功能介绍
May 18 HTML / CSS
原生canvas制作画图小工具的踩坑和爬坑
Jun 09 HTML / CSS
HTML基础-标签分类(闭合标签,空标签,块级元素,行内元素,行级块元素,可替换元素)
Mar 31 HTML / CSS
HTML通过表单实现酒店筛选功能
May 18 HTML / CSS
Canvas globalCompositeOperation
Dec 18 #HTML / CSS
深入理解HTML5定时器requestAnimationFrame的使用
Dec 12 #HTML / CSS
手对手的教你用canvas画一个简单的海报的方法示例
Dec 10 #HTML / CSS
html5+css如何实现中间大两头小的轮播效果
Dec 06 #HTML / CSS
Html5 Canvas动画基础碰撞检测的实现
Dec 06 #HTML / CSS
canvas压缩图片以及卡片制作的方法示例
Dec 04 #HTML / CSS
canvas探照灯效果的示例代码
Nov 30 #HTML / CSS
You might like
日本因肺炎疫情影响,这几部动漫推延播放!
2020/03/03 日漫
thinkphp5.0自定义验证规则使用方法
2017/11/16 PHP
php使用yield对性能提升的测试实例分析
2019/09/19 PHP
Jquery在IE7下无法使用 $.ajax解决方法
2009/11/11 Javascript
js对图片base64编码字符串进行解码并输出图像示例
2014/03/17 Javascript
使用JS中的exec()方法构造正则表达式验证
2016/08/01 Javascript
JavaScript递归函数定义与用法实例分析
2019/01/24 Javascript
JavaScript数组排序功能简单实现
2020/05/14 Javascript
详解React 条件渲染
2020/07/08 Javascript
nodejs中内置模块fs,path常见的用法说明
2020/11/07 NodeJs
[06:45]DOTA2卡尔工作室 英雄介绍幻影长矛手篇
2013/07/12 DOTA
[02:51]2014DOTA2 TI小组赛总结中国军团全部进军钥匙球馆
2014/07/15 DOTA
[59:08]DOTA2上海特级锦标赛C组小组赛#2 LGD VS Newbee第一局
2016/02/27 DOTA
Python与shell的3种交互方式介绍
2015/04/11 Python
python解析xml文件实例分析
2015/05/27 Python
python中__call__内置函数用法实例
2015/06/04 Python
使用python实现BLAST
2018/02/12 Python
Python实现输入二叉树的先序和中序遍历,再输出后序遍历操作示例
2018/07/27 Python
500行Python代码打造刷脸考勤系统
2019/06/03 Python
python中多个装饰器的调用顺序详解
2019/07/16 Python
python redis连接 有序集合去重的代码
2019/08/04 Python
Python列表推导式实现代码实例
2020/09/09 Python
提高python代码运行效率的一些建议
2020/09/29 Python
Ubuntu16安装Python3.9的实现步骤
2020/12/15 Python
利用CSS3实现的文字定时向上滚动
2016/08/29 HTML / CSS
优秀学生干部个人的自我评价
2013/10/04 职场文书
揭牌仪式主持词
2014/03/19 职场文书
公司寄语大全
2014/04/10 职场文书
甜品店创业计划书
2014/08/14 职场文书
七一建党日演讲稿
2014/09/05 职场文书
故宫的导游词
2015/01/31 职场文书
中秋晚会致辞
2015/07/31 职场文书
安全生产学习心得体会
2016/01/18 职场文书
2019七夕节祝福语36句,快来收藏吧
2019/08/06 职场文书
一文带你探究MySQL中的NULL
2021/11/11 MySQL
mysql insert 存在即不插入语法说明
2022/03/25 MySQL