html2canvas 網頁截圖

網頁截圖應用-html2canvas問題研究

葉文華 2019/04/02 10:00:00
75

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 HeadersCORS)Canvas時,將不能使用其toBolb()toDataURL()getImageData()等方法,即代表無法達成圖片進行上傳或下載的保存需求。

 

html2canvas提供了參數allowTaintproxyuseCORS及輔助處理跨域圖片的需求,但在應用場景有所不同:

⇒allowTaint=true,可以繼續繪製跨域圖片(Response HeadersCORS)canvas上,但只能在網頁上直接顯示canvas,此參數無法與useCORS同時使用(會報錯)

proxy設定,可以協助載入跨域圖片(Response HeadersCORS),但將會是一項額外的系統建置成本。

ps. proxy代理的方式思考,即是讓Canvas認為該圖片是同域即可。故可由網頁後端程式代理輸出(client to local server to remote server),或由網頁後端程式直接保存為Data URLs輸出,仍是可以考慮的替代方案。

 

useCORS=true,可以繼續繪製跨域圖片(Response HeadersCORS)canvas上,並可正常用toBolb()toDataURL()getImageData()等方法輸出並保存圖片。

3.4 多張截圖要注意執行完成的順序

這個本是javascript特性需要注意的問題,在需要截取多張圖片時,由於截圖處理的時間不一樣,造成順序的不一致,如果有相關檢核條件或對順序有要求就必須要注意這個狀況。

console log觀察到先截圖的page=0較慢執行完成:

在輸出截圖在畫面時就可能會出現顛倒的結果:

4. 結論及補充

html2canvas是一種前端網頁截圖的作法,但仍有樣式不一致問題(不同瀏覽器效果不一樣,以及同一瀏覽器顯示與截圖結果不一樣),對網頁樣式的支援仍待持續改進,現階段的應用上只能靠前端的設計或開發來避開。跨域圖片問題,由於安全性議題無可避免,在實務應用上除了html2canvs提供解決方式外,也可考慮前述3.3中描述替代方案以應對實際需求。

網頁保存為圖片也有後端處理的選項,不過仍有JDK原生支援性、後端顯示硬體(或顯示模擬)以及額外安裝工具元件(例:Headless Browsers)等問題,則不在此篇探討的範圍。

 

葉文華