最近写项目有用到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+`" >
。
然后就可以看到界面上显示的图片了:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 小骆驼-《草原狼2(蓝光CD)》[原抓WAV+CUE]
- 群星《欢迎来到我身边 电影原声专辑》[320K/MP3][105.02MB]
- 群星《欢迎来到我身边 电影原声专辑》[FLAC/分轨][480.9MB]
- 雷婷《梦里蓝天HQⅡ》 2023头版限量编号低速原抓[WAV+CUE][463M]
- 群星《2024好听新歌42》AI调整音效【WAV分轨】
- 王思雨-《思念陪着鸿雁飞》WAV
- 王思雨《喜马拉雅HQ》头版限量编号[WAV+CUE]
- 李健《无时无刻》[WAV+CUE][590M]
- 陈奕迅《酝酿》[WAV分轨][502M]
- 卓依婷《化蝶》2CD[WAV+CUE][1.1G]
- 群星《吉他王(黑胶CD)》[WAV+CUE]
- 齐秦《穿乐(穿越)》[WAV+CUE]
- 发烧珍品《数位CD音响测试-动向效果(九)》【WAV+CUE】
- 邝美云《邝美云精装歌集》[DSF][1.6G]
- 吕方《爱一回伤一回》[WAV+CUE][454M]