本次技術調研來源於H5項目中的一個重要功能需求:實現微信長按網頁保存爲截圖
。css
這裏有個栗子(請用微信打開,長按圖片便可保存):3分鐘探索你的知識邊界html
將整個網頁保存爲圖片是一個十分有趣的功能,常見於H5活動頁的結尾頁分享。如下則是項目中調研和踩坑的一些小結和彙總。html5
現有已知可以實現網頁保存爲圖片的方案包括:git
data URI
html2canvas.js
實現(可選搭配Canvas2Image.js
實現網頁保存爲圖片)rasterizeHTML.js
實現方案1:須要手動計算每一個DOM元素的Computed Style
,而後須要計算好元素在canvas的大小位置等屬性。github
方案1難點
:web
小結
: html2canvas是目前實現網頁保存爲圖片功能的綜合最佳選擇。chrome
官方GitHub:https://github.com/niklasvh/h...canvas
如下描述針對html2canvas版本是0.5.0-beta4
segmentfault
基於html2canvas.js
可將一個元素渲染爲canvas,只須要簡單的調用html2canvas(element[, options]);
便可。下列html2canvas
方法會返回一個包含有<canvas>
元素的promise
:跨域
html2canvas(document.body).then(function(canvas) { document.body.appendChild(canvas); });
上一步生成的canvas即爲包含目標元素的<canvas>
元素對象。實現保存圖片的目標只須要將canvas轉image便可。
這裏的轉換方案有2種
:
toDataURL
方法將canvas輸出爲data: URI
類型的圖片地址,再將該圖片地址賦值給<image>
元素的src屬性便可Canvas2Image.js
,調用其convertToImage
方法便可(GitHub)實際上,Canvas2Image.js
也是基於canvas.toDataURL
的封裝,相比原生的canvas API對於轉爲圖片的功能上考慮更爲具體(未壓縮的包大小爲7.4KB),適合項目使用。
最終圖片的清晰度
取決於
第一步中html轉換成的canvas的清晰度。
現有解決方案參考;
其基本原理爲:
將canvas
的屬性width
和height
屬性放大爲2倍(或者設置爲devicePixelRatio
倍),最後將canvas的CSS樣式width和height設置爲原先1倍的大小。
例如:但願在html中實際顯示的<canvas>
寬高分別爲160px
,90px
則可做以下設置
<canvas width="320" height="180" style="width:160px;height:90px;"></canvas>
參考上述文檔具體的使用案例以下;
convert2canvas() { var shareContent = YourTargetElem; var width = shareContent.offsetWidth; var height = shareContent.offsetHeight; var canvas = document.createElement("canvas"); var scale = 2; canvas.width = width * scale; canvas.height = height * scale; canvas.getContext("2d").scale(scale, scale); var opts = { scale: scale, canvas: canvas, logging: true, width: width, height: height }; html2canvas(shareContent, opts).then(function (canvas) { var context = canvas.getContext('2d'); var img = Canvas2Image.convertToImage(canvas, canvas.width, canvas.height); document.body.appendChild(img); $(img).css({ "width": canvas.width / 2 + "px", "height": canvas.height / 2 + "px", }) }); }
上述設置能夠解決一般的截圖效果不清晰問題,不過探索還遠沒有結束。
實際在咱們的項目中,即便做出2.1節
的設置後,模糊成大果粒的渲染結果依然給清晰的幻想打了0分。
下面直接給出3條進一步的優化策略:
百分比佈局
爲px佈局
(若是原先是百分比佈局的話)關閉
canvas默認的抗鋸齒設
置width
和height
爲素材原有寬高,而後經過transform: scale
進行縮放。這裏scale
的數值由具體需求決定。基本原理
px爲單位
的寬高,避免樣式二次計算致使的模糊關閉抗鋸齒
來實現圖像的銳化(MDN: imageSmoothingEnabled )css樣式
的scale
來實現一樣的縮放例: html2canvas配置
convert2canvas() { var cntElem = $('#j-sec-end')[0]; var shareContent = cntElem;//須要截圖的包裹的(原生的)DOM 對象 var width = shareContent.offsetWidth; //獲取dom 寬度 var height = shareContent.offsetHeight; //獲取dom 高度 var canvas = document.createElement("canvas"); //建立一個canvas節點 var scale = 2; //定義任意放大倍數 支持小數 canvas.width = width * scale; //定義canvas 寬度 * 縮放 canvas.height = height * scale; //定義canvas高度 *縮放 canvas.getContext("2d").scale(scale, scale); //獲取context,設置scale var opts = { scale: scale, // 添加的scale 參數 canvas: canvas, //自定義 canvas // logging: true, //日誌開關,便於查看html2canvas的內部執行流程 width: width, //dom 原始寬度 height: height, useCORS: true }; html2canvas(shareContent, opts).then(function (canvas) { var context = canvas.getContext('2d'); context.mozImageSmoothingEnabled = false; context.webkitImageSmoothingEnabled = false; context.msImageSmoothingEnabled = false; context.imageSmoothingEnabled = false; var img = Canvas2Image.convertToJPEG(canvas, canvas.width, canvas.height); document.body.appendChild(img); $(img).css({ "width": canvas.width / 2 + "px", "height": canvas.height / 2 + "px", // 'border': '10px solid #000' }).addClass('f-full'); $('#j-sec-end').remove(); }); }
例: DOM元素樣式:
.targetElem {width: 54px;height: 142px;margin-top:2px;margin-left:17px;transform: scale(0.5)}
<!--## 2.3 優化結果對比
(mac中有截圖,能夠對比)-->
因爲canvas對於圖片資源的同源限制
,若是畫布中包含跨域的圖片資源則會污染畫布,形成生成圖片樣式混亂或者html2canvas方法不執行等問題。
如下主要解決兩類跨域的圖片資源:包括已配置過CORS的CDN
中的圖片資源和微信用戶頭像
圖片資源。
CORS
。CDN
配置好後,經過chrome開發者工具能夠看到響應頭中應含有Access-Control-Allow-Origin
的字段。html2canvas
的useCORS
配置項。即做以下設置:
useCORS: true } html2canvas(element, options);
注意
:
若是沒有開啓html2canvas
的useCORS
配置項,html2canvas
會正常執行且不會報錯,可是不會輸出對應的CDN圖片
(即在同一頁面中,可測試同時包含CDN的圖片
和本地圖片
的資源的頁面,可是隻有本地圖片
可以被正常渲染出來)
若是須要將微信
平臺中的用戶頭像一併保存爲圖片,3.1
的方案無能爲力。可經過配置代理轉發
實現,此處不贅述。
微信中,喚出長按保存圖片
的菜單要求長按的對象直接是<image>
元素,若是<image>
元素上方存在遮擋,則不會喚出菜單。
而事實上,引起遮擋的並不僅是非<image>
元素,還多是margin
屬性。例如:若在頁面底部,對一個絕對定位的元素設置了數值很大的margin-top
,則margin-top
所涉及的區域,均沒法長按喚出菜單。解決方案:將margin-top
改用爲top
便可。
canvas2img
默認保存圖片的格式爲png
,而在安卓版微信中所生成的圖片儘管能長按喚出保存圖片的菜單,可是沒法正確保存到本地相冊。 解決方案
:設置canvas2img
的生成圖片格式配置項爲jpeg
便可。
設置canvas2img
輸出格式爲jpeg
,會有必定概率致使生成的圖片包含大量的黑色塊。可能的解決方案
:減少圖片元素的體積大小和背景圖片的尺寸大小。
在圖片的轉化前
,必須中止
或者刪除動效後才能正確渲染出圖片,不然生成的圖片是破裂的。