這幾天在做入學(xué)診斷測(cè)試報(bào)告,需要將頁(yè)面轉(zhuǎn)成圖片做分享,首先會(huì)想到到的方案有:
1辨泳、利用canvas重新繪制整個(gè)頁(yè)面虱岂,但是需要手動(dòng)將整個(gè)頁(yè)面上所有的元素,然后需要計(jì)算好元素在canvas的大小位置等屬性菠红,工作量非常大第岖,另外由于canvas中沒有的對(duì)象概念,對(duì)于元素豐富试溯、布局復(fù)雜的頁(yè)面蔑滓,不易重構(gòu)。
2遇绞、后臺(tái)利用java swing繪制键袱,這種方案也和上面方案一樣,對(duì)于簡(jiǎn)單圖片的繪制還能嘗試摹闽,對(duì)內(nèi)容很復(fù)雜的整個(gè)網(wǎng)頁(yè)進(jìn)行繪制也是非常的難蹄咖,畫出來(lái)效果也很難保證。
所以在著手開始做這項(xiàng)工作的時(shí)候就考慮尋求更佳的方案付鹿,經(jīng)調(diào)研采取html2canvas插件來(lái)做澜汤,官網(wǎng):http://html2canvas.hertzen.com/ .
該插件能夠通過(guò)純JS的方式將整個(gè)頁(yè)面指定元素轉(zhuǎn)換成canvas,同時(shí)調(diào)用非常簡(jiǎn)單倘屹,能夠節(jié)約大量的開發(fā)時(shí)間银亲,總體方案就是通過(guò)html2canvas將dom轉(zhuǎn)換為canvas,然后通過(guò)canvas.toDataURL() 方法轉(zhuǎn)化為base64纽匙,二進(jìn)制流的圖片,顯示在頁(yè)面上拍谐。
下面我就從插件的使用及遇到的問(wèn)題做下總結(jié)烛缔。
使用說(shuō)明
1、插件源碼獲取
目前該項(xiàng)目已經(jīng)托管在github上轩拨,github地址為https://github.com/niklasvh/html2canvas
支持npm下載践瓷,通過(guò)npm下載后,在dist文件中找到html2canvas.js亡蓉,只需要這一個(gè)文件就可以晕翠。
2、調(diào)用方式
html2canvas(element, opts).then(function (canvas) {
});
element為要轉(zhuǎn)成圖片的元素
opts為配置對(duì)象
后面的function為回調(diào)函數(shù)砍濒。
3淋肾、配置對(duì)象說(shuō)明
參見下表,下圖中紅色圈中的幾個(gè)配置項(xiàng)比較重要爸邢,本次調(diào)用中都使用到了樊卓。
4、canvas轉(zhuǎn)圖片
canvas.toDataURL()轉(zhuǎn)換成base64杠河,然后保存到事先隱藏的img中
遇到的問(wèn)題
1碌尔、跨域圖片的問(wèn)題
????該插件對(duì)于跨域圖片問(wèn)題需要設(shè)置useCORS為true浇辜,同時(shí)在圖片上添加屬性crossOrigin:anonymous,然后在通過(guò)proxy設(shè)置請(qǐng)求圖片地址唾戚,然后再重新下載地址柳洋,也就是這個(gè)插件支持的跨域只能是自己可管控的服務(wù)器,因?yàn)樾枰诜?wù)器端設(shè)置允許跨域叹坦。而我們測(cè)試報(bào)告中存在的圖片大多保存在阿里云oss上膳灶,所以這個(gè)問(wèn)題基本就卡住了。
????后面轉(zhuǎn)變了下思路立由,能不能將跨域圖片改為不跨域呢轧钓,就考慮將我們圖片src屬性改為我們自己的域名地址。于是在smartwork后臺(tái)添加了一個(gè)接口锐膜,通過(guò)該接口去請(qǐng)求阿里云oss的圖片毕箍,然后以流的方式寫到客戶端(瀏覽器)。最后將我們所有跨域圖片的地址都改為該接口地址:
src="<%=basePath%>/free/entry/downloadOssPic.html?url=${fileurl }${jpq.aImg1}"
參數(shù)為阿里云圖片的地址道盏。
2而柑、圖片清晰度的問(wèn)題
生成后的圖片比較模糊,由于該插件支持自己聲明初始化canvas對(duì)象傳入荷逞,所以考慮放大canvas的坐標(biāo)系媒咳,生成比較大的圖片,然后拿到生成的canvas轉(zhuǎn)成base64保存到圖片中种远,同時(shí)將圖片大小設(shè)置原先頁(yè)面同等大小涩澡。可以根據(jù)自己的需求設(shè)定放大的倍數(shù)坠敷。具體代碼如下:
????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);
? ? 回調(diào)中設(shè)置圖片妙同,$("#predict_img").attr('src',canvas.toDataURL()).css("width",width+"px").css("height","auto");
在本地測(cè)試將scale設(shè)置較大以后,確實(shí)能夠改善圖片質(zhì)量膝迎,但是該值設(shè)計(jì)較大以后粥帚,生成canvas的時(shí)間會(huì)變得比較長(zhǎng),目前線上將該值設(shè)置為2限次。
3芒涡、避免多次圖片生成
這里主要是一些dom操作上的技巧,因?yàn)楸苊舛啻紊赏粡垐D片卖漫,所以報(bào)告和分享圖在同一個(gè)頁(yè)面费尽,分開頁(yè)面必然會(huì)造成多次canvas繪制,不僅影響客戶端性能懊亡,還會(huì)多次請(qǐng)求后臺(tái)資源依啰。
事先在頁(yè)面底部放了一個(gè)隱藏的div,其中放了一張空?qǐng)D片店枣,生成canvas后速警,填充該圖片叹誉,展示隱藏div,同時(shí)將頁(yè)面中的其他元素隱藏闷旧。返回時(shí)长豁,與以上操作相反。下次點(diǎn)擊分享時(shí)忙灼,判斷圖片是否為空匠襟,不為空時(shí)只需要控制頁(yè)面元素展示與隱藏就可以。
由于測(cè)試報(bào)告上線時(shí)間比較倉(cāng)促该园,調(diào)研得不是很充分酸舍,目前圖片還是有些模糊,后面有時(shí)間再對(duì)該插件進(jìn)行深入調(diào)研里初。