最近一個產品需要是把微信服務號中一個網頁內容生成一張圖片,使用者長按可以儲存為圖片,圖片中的二維碼可以識別,圖片中包含使用者頭像。效果如圖1-1
最常用的做法是把網頁轉換為cancas,接著轉成圖片,最流行的外掛是html2canvas。官網的文件個人感覺不是特別好。html2canvas.hertzen.com/具體做法參考了此部落格。segmentfault.com/a/119000001…。
圖1-1
紅色圓圈位置應該為微信頭像的位置,web端獲取不到用紅圈代替。右下角二維碼是根據後端資料渲染出來的動態二維碼。
整個需求難點和坑分為幾部分:
1.獲取頭像並且可以儲存到canvas生成的img中(canvas對於跨域圖片的處理一般是在原圖片處顯示空白---需要後端配合)
2.生成canvas比生成二維碼或微信頭像快,導致二維碼沒有附在canvas生成的整圖中(非同步處理,安排事件執行順序)
3.設定canvas寬高為背景大圖帶小數的原始尺寸(通過offsetWidth width等獲得的是取整之後的寬度 )以及偏移尺寸。
4.圖片清晰度處理(設定canvas畫布縮放比)
1.處理canvas中跨域的問題,微信頭像和自己的伺服器必然不在同一個域,那首先需要前端設定canvas的配置項,允許跨域。網上有幾種做法可以參考
1.1將微信頭像上傳到自己伺服器,再返回前段圖片地址,就不會涉及跨域問題。
1.2在NGINX上設定反向代理,把微信頭像域名地址換成自己伺服器的。(但是一旦微信頭像更新域名這種做法就會出bug )參考資料blog.csdn.net/mengruobaob…
location ^~ /wechat_image/ {
add_header 'Access-Control-Allow-Origin' "$http_origin" always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified- Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;
proxy_pass http://wx.qlogo.cn/;
}
複製程式碼
然後將微信的頭像 wx.qlogo.cn/xxx => https://${自己的域名}/wechat_image/xxx和後端協商好下劃線部分。
2.非同步處理可以涉及很多內容,筆者自己也不是特別懂,此處不展開講,下次專門出一篇非同步的部落格。此處處理將替換頭像地址,生成動態二維碼,canvas繪圖按照前中後三步順序執行,(沒有做非同步處理時,safiri中生成canvas比生成頭像和生成二維碼都快,導致最後的整圖沒有微信頭像和二維碼。)
3.生成canvas過程中會發現二維碼的位置會在開啟頁面一秒左右往上方偏移一下,一開始以為是因為生成的畫布以及圖片和之前的dom節點高度不同,所以設定了畫布高度時採用了getBoundingClientRect()獲得實際dom元素寬高,以及生成畫布過程中可能出現的偏移。
4.設定canvas的縮放scale。
程式碼如下:
// $(function() {
function imgUrlChange(){
var wximg = $("#wximg").attr('src');
if(wximg){
var newimg = window.location.origin +'/wechat_image'+ wximg.split("http://thirdwx.qlogo.cn")[1];
}else{
console.log('微信頭像沒有讀取到');
}
$("#wximg").attr('src',newimg);
}
function shareQRCode () {
return new Promise (function(resolve,reject){
setTimeout(function() {
var shareid = $("#urldata").attr('uid');
var qrcode = new QRCode('qrcode', {
text: 'your content',
width: 90,
height: 90,
correctLevel: QRCode.CorrectLevel.H
});
//使用 API
qrcode.clear();
qrcode.makeCode(shareid);
console.log(2);
resolve();
},0)
})
}
function canvasImg (){
console.log(3)
setTimeout(function(){
var cntElem = $('#html2canvas')[0];
var shareContent = cntElem;//需要截圖的包裹的(原生的)DOM 物件
var cont = cntElem.getBoundingClientRect();
var width = cont.width; //獲取dom 寬度
var height = cont.height; //獲取dom 高度
var canvas = document.createElement("canvas"); //建立一個canvas節點
var scale = 2; //定義任意放大倍數 支援小數
canvas.width = width * scale; //定義canvas 寬度 * 縮放
canvas.height = height * scale; //定義canvas高度 *縮放
var context = canvas.getContext("2d");
context.scale(scale, scale); //獲取context,設定scale
context.translate(-cont.left,-cont.top);//設定context位置,值為相對於視窗的偏移量負值,讓圖片復位
var opts = {
scale: scale, // 新增的scale 引數
canvas: canvas, //自定義 canvas
// logging: true, //日誌開關,便於檢視html2canvas的內部執行流程
width: width, //dom 原始寬度
height: height,
useCORS: true // 【重要】開啟跨域配置
};
html2canvas(shareContent, opts).then(function (canvas) {
// 【重要】關閉抗鋸齒
context.mozImageSmoothingEnabled = false;
context.webkitImageSmoothingEnabled = false;
context.msImageSmoothingEnabled = false;
context.imageSmoothingEnabled = false;
// 【重要】預設轉化的格式為png,也可設定為其他格式
var image = canvas.toDataURL("image/png");
var pHtml = "<img src="+image+" />";
$('#html2canvas').html(pHtml);
$('#html2canvas>img').css({
"width": 100 + "%",
"height":height,
});
}, 200)
});
}
imgUrlChange()
shareQRCode().then(function() { canvasImg() }) // })複製程式碼