網頁截圖應用-html2canvas問題研究
1. 工具
-
Chrome
-
html2canvas.js
-
jQuery
2. 開始截圖前的準備
2.1 網頁內容
準備了兩段內容,一段主要為圖片內容,另一段是文字內容,用作展示截圖效果並會加以說明目前應用上的困難。
2.1.1 如下圖片內容,在測試網頁的網址為「http://127.0.0.1:8080/...」,而圖片網址(http://192.168.8.105:8080)則採用不同的位址來源,重現跨域問題。
2.1.2 如下文字內容,在Windows版的Chrome瀏覽器上直接目視及桌面版截圖程式截取效果的表現,觀察樣式符合需求。
2.2 測試程式
var pages = $('.page');
var pageNumber = pages.length;
pages.each(function( index ) {
var w = $(this)[0].offsetWidth;
var h = $(this)[0].offsetHeight;
var canvas = document.createElement('canvas');
var scale = 2;
canvas.width = w * scale ;
canvas.height = h * scale ;
var context = canvas.getContext('2d');
console.log("width=" + w + ", height=" + h);
//cal canvas scale
context.scale(scale,scale);
html2canvas($(this)[0], {canvas:canvas, scale:scale, useCORS:true}).then(function(canvas) {
console.log("page = " + index);
var image = canvas.toDataURL("image/png", 1.0);
var createImg = document.createElement('img');
createImg.setAttribute('id', 'page'+index);
createImg.setAttribute('src', image);
document.body.appendChild(createImg);
});
});
3. 截圖過程中容易碰到的問題
3.1 截圖結果清晰度問題
程式中定義了scale = 2,設定一般性原則讓Canvas寬高為2倍且內容以scale比例縮放。
var scale = 2;
...
canvas.width = w * scale ;
canvas.height = h * scale ;
...
context.scale(scale,scale);
並且在html2canvas中設定其scale(預設window.devicePixelRatio),可達到普遍可接受的清晰度。
html2canvas($(this)[0], {canvas:canvas, scale:scale, useCORS:true})...
程式中還有canvas.toDataURL參數quality=1.0,不過此參數最高即為1.0原始品質,縮小數字即降低品質,故對提升清晰度沒有幫助,只能另作其他降低品質的用途。
canvas.toDataURL("image/png", 1.0)
3.2 截圖結果內容呈現與原網頁內容樣式不一致問題
通過截圖後,可以發現部分樣式已經不符合需求,
(可以參考官方支援、不支援的項目列表:http://html2canvas.hertzen.com/features)
如:在不同瀏覽器上截取圖片,畫質效果不一(包含顏色、清晰度都不一致)。
如:有些底線沒有繪出來,或是繪出的底線並未切齊文字下方。
在實作過程中驗證還有發現字體大小比例不對、文字折行樣式未生效...等問題。
3.3 截圖結果中原網頁內容圖片區塊空白問題
html2canvas作法是透過繪製網頁dom元素到Canvas,再經由Canvas輸出成圖片,故受限於Canvas同域原則,在渲染了跨域圖片(且Response Headers無CORS)到Canvas時,將不能使用其toBolb()、toDataURL()或getImageData()等方法,即代表無法達成圖片進行上傳或下載的保存需求。
html2canvas提供了參數allowTaint、proxy及useCORS及輔助處理跨域圖片的需求,但在應用場景有所不同:
⇒allowTaint=true,可以繼續繪製跨域圖片(且Response Headers無CORS)到canvas上,但只能在網頁上直接顯示canvas,此參數無法與useCORS同時使用(會報錯)。
⇒proxy設定,可以協助載入跨域圖片(且Response Headers無CORS),但將會是一項額外的系統建置成本。
ps. 以proxy代理的方式思考,即是讓Canvas認為該圖片是同域即可。故可由網頁後端程式代理輸出(client to local server to remote server),或由網頁後端程式直接保存為Data URLs輸出,仍是可以考慮的替代方案。
⇒useCORS=true,可以繼續繪製跨域圖片(且Response Headers有CORS)到canvas上,並可正常用toBolb()、toDataURL()或getImageData()等方法輸出並保存圖片。
3.4 多張截圖要注意執行完成的順序
這個本是javascript特性需要注意的問題,在需要截取多張圖片時,由於截圖處理的時間不一樣,造成順序的不一致,如果有相關檢核條件或對順序有要求就必須要注意這個狀況。
console log觀察到先截圖的page=0較慢執行完成:
在輸出截圖在畫面時就可能會出現顛倒的結果:
4. 結論及補充
html2canvas是一種前端網頁截圖的作法,但仍有樣式不一致問題(不同瀏覽器效果不一樣,以及同一瀏覽器顯示與截圖結果不一樣),對網頁樣式的支援仍待持續改進,現階段的應用上只能靠前端的設計或開發來避開。跨域圖片問題,由於安全性議題無可避免,在實務應用上除了html2canvs提供解決方式外,也可考慮前述3.3中描述替代方案以應對實際需求。
網頁保存為圖片也有後端處理的選項,不過仍有JDK原生支援性、後端顯示硬體(或顯示模擬)以及額外安裝工具元件(例:Headless Browsers)等問題,則不在此篇探討的範圍。