这几天在做入学诊断测试报告,需要将页面转成图片做分享,首先会想到到的方案有:
1、利用canvas重新绘制整个页面,但是需要手动将整个页面上所有的元素,然后需要计算好元素在canvas的大小位置等属性,工作量非常大,另外由于canvas中没有的对象概念,对于元素丰富、布局复杂的页面,不易重构。
2、后台利用java swing绘制,这种方案也和上面方案一样,对于简单图片的绘制还能尝试,对内容很复杂的整个网页进行绘制也是非常的难,画出来效果也很难保证。
所以在着手开始做这项工作的时候就考虑寻求更佳的方案,经调研采取html2canvas插件来做,官网:http://html2canvas.hertzen.com/ .
该插件能够通过纯JS的方式将整个页面指定元素转换成canvas,同时调用非常简单,能够节约大量的开发时间,总体方案就是通过html2canvas将dom转换为canvas,然后通过canvas.toDataURL() 方法转化为base64,二进制流的图片,显示在页面上。
下面我就从插件的使用及遇到的问题做下总结。
使用说明
1、插件源码获取
目前该项目已经托管在github上,github地址为https://github.com/niklasvh/html2canvas
支持npm下载,通过npm下载后,在dist文件中找到html2canvas.js,只需要这一个文件就可以。
2、调用方式
html2canvas(element, opts).then(function (canvas) {
});
element为要转成图片的元素
opts为配置对象
后面的function为回调函数。
3、配置对象说明
参见下表,下图中红色圈中的几个配置项比较重要,本次调用中都使用到了。
4、canvas转图片
canvas.toDataURL()转换成base64,然后保存到事先隐藏的img中
遇到的问题
1、跨域图片的问题
该插件对于跨域图片问题需要设置useCORS为true,同时在图片上添加属性crossOrigin:anonymous,然后在通过proxy设置请求图片地址,然后再重新下载地址,也就是这个插件支持的跨域只能是自己可管控的服务器,因为需要在服务器端设置允许跨域。而我们测试报告中存在的图片大多保存在阿里云oss上,所以这个问题基本就卡住了。
后面转变了下思路,能不能将跨域图片改为不跨域呢,就考虑将我们图片src属性改为我们自己的域名地址。于是在smartwork后台添加了一个接口,通过该接口去请求阿里云oss的图片,然后以流的方式写到客户端(浏览器)。最后将我们所有跨域图片的地址都改为该接口地址:
src="<%=basePath%>/free/entry/downloadOssPic.html?url=${fileurl }${jpq.aImg1}"
参数为阿里云图片的地址。
2、图片清晰度的问题
生成后的图片比较模糊,由于该插件支持自己声明初始化canvas对象传入,所以考虑放大canvas的坐标系,生成比较大的图片,然后拿到生成的canvas转成base64保存到图片中,同时将图片大小设置原先页面同等大小。可以根据自己的需求设定放大的倍数。具体代码如下:
var width = $("#contbox").outerWidth();
var height = $("#contbox").outerHeight();
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
var scale = 2;
canvas.width = width * scale;
canvas.height = height * scale;
canvas.getContext("2d").scale(scale, scale);
回调中设置图片,$("#predict_img").attr('src',canvas.toDataURL()).css("width",width+"px").css("height","auto");
在本地测试将scale设置较大以后,确实能够改善图片质量,但是该值设计较大以后,生成canvas的时间会变得比较长,目前线上将该值设置为2。
3、避免多次图片生成
这里主要是一些dom操作上的技巧,因为避免多次生成同一张图片,所以报告和分享图在同一个页面,分开页面必然会造成多次canvas绘制,不仅影响客户端性能,还会多次请求后台资源。
事先在页面底部放了一个隐藏的div,其中放了一张空图片,生成canvas后,填充该图片,展示隐藏div,同时将页面中的其他元素隐藏。返回时,与以上操作相反。下次点击分享时,判断图片是否为空,不为空时只需要控制页面元素展示与隐藏就可以。
由于测试报告上线时间比较仓促,调研得不是很充分,目前图片还是有些模糊,后面有时间再对该插件进行深入调研。