html dom 轉化成圖片踩坑記(canvas toDataURL)

需求

在開發過程當中遇到這麼一個需求,h5頁面須要將一個html dom轉化成圖片,便於用戶保存。html

面向百度搜索第三方得 html2canvas 和 dom-to-image

二者在寫這篇筆記以前在github上的星星數分別是ios

dom-to-image 4k ⭐️git

html2canvas 13.7k ⭐️github

二者都有嘗試過,都有意想不到的bug,包括canvas

  1. 部分手機有某些背景圖片沒法展現,爲空白
  2. iphone8 plus ios 11中根本不調用這個轉換方法,從而得不到想要的圖片。

等等跨域

本身動手

思路

利用canvas的toDataURL來拿到canvas轉化的base64碼,來替換img的url, 也能夠把圖片上傳到公司的服務器上,獲得圖片的地址來進行下載,或做爲參數來傳遞瀏覽器

那麼canvas的繪製主要就是文本和圖片的繪製,文本繪製相對簡單,圖片繪製有一些注意點。服務器

canvas 初始化

因爲最後生成的圖片可能會模糊,能夠儘可能畫大一點畫布,能夠按照設計圖來dom

<canvas id="canvas" width="750" height="1164">
  你的瀏覽器竟然不支持Canvas?!趕快換一個吧!!
</canvas>
let c = document.getElementById("canvas");
let ctx = c.getContext("2d");

文本繪製

官方文檔如圖

圖片描述

詳細文檔請參考 canvas手冊

代碼示例

ctx.fillStyle = "#fff";
ctx.font = "32px PingFangSC-Regular";
ctx.textAlign = "left";
ctx.fillText("這是一些文字", 280, 755);

圖片繪製

官方文檔如圖

圖片描述

詳細文檔請參考 canvas手冊

注意事項

  1. 圖片須要進行跨域處理,不然後期沒法生成圖片,也就是在img標籤中增長crossOrigin屬性,值爲anonymous
const instBanner = document.getElementById("instBanner");
instBanner.crossOrigin = "anonymous";
  1. 須要等到圖片加載完成再畫到畫布上,不然有可能沒畫上去
const posterBg = new Image();
posterBg.src = mainBg;
posterBg.onload = () => {
  ctx.drawImage(posterBg, 0, 0, 750, 1164);
}

完整代碼示例

const posterBg = new Image();
posterBg.src = 'https:....'; //這裏是圖片url
posterBg.crossOrigin = "anonymous";
posterBg.onload = () => {
  ctx.drawImage(posterBg, 0, 0, 750, 1164);
}

生成圖片

替換img src

let dataURL = c.toDataURL("image/png");
let canvasImg = document.getElementById("canvasImg");
canvas.src = dataURL;

上傳服務器,獲得img url(可做爲參數,保存圖片)

let dataURL = c.toDataURL("image/png");
function getImgUrl(dataURL){
  //一些上傳服務器的代碼
  return imgUrl
}
let imgUrl = getImgUrl();
let canvasImg = document.getElementById("canvasImg");
canvas.src = imgUrl;

最後奉上一些,經常使用的canvas處理方法

圓形圖片的繪製

ctx.save();

ctx.beginPath(); //開始繪製
//先畫個圓   前兩個參數肯定了圓心 (x,y) 座標  第三個參數是圓的半徑  四參數是繪圖方向  默認是false,即順時針
ctx.arc(60, 60, 30, 0 * Math.PI, 2 * Math.PI);

ctx.clip();//畫好了圓 剪切  原始畫布中剪切任意形狀和尺寸。一旦剪切了某個區域,則全部以後的繪圖都會被限制在被剪切的區域內 這也是咱們要save上下文的緣由

ctx.drawImage('https:....', 30, 30, 60, 60);

contex.restore(); //恢復以前保存的繪圖上下文 恢復以前保存的繪圖上下午即狀態 還能夠繼續繪製

圓角矩形繪製

/**該方法用來繪製圓角矩形 
*@param cxt:canvas的上下文環境 
*@param x:左上角x軸座標 
*@param y:左上角y軸座標 
*@param width:矩形的寬度 
*@param height:矩形的高度 
*@param radius:圓的半徑 
*@param lineWidth:線條粗細 
*@param strokeColor:線條顏色 
**/  
function strokeRoundRect(cxt,x,y,width,height,radius,/*optional*/lineWidth,/*optional*/strokeColor){  
    //圓的直徑必然要小於矩形的寬高          
    if(2*radius>width || 2*radius>height){return false;}  
      
    cxt.save();  
    cxt.translate(x,y);  
    //繪製圓角矩形的各個邊  
    drawRoundRectPath(cxt,width,height,radius);  
    cxt.lineWidth = lineWidth||2;//如果給定了值就用給定的值不然給予默認值2  
    cxt.strokeStyle=strokeColor||"#000";  
    cxt.stroke();  
    cxt.restore();  
}  

/**該方法用來繪製一個有填充色的圓角矩形 
*@param cxt:canvas的上下文環境 
*@param x:左上角x軸座標 
*@param y:左上角y軸座標 
*@param width:矩形的寬度 
*@param height:矩形的高度 
*@param radius:圓的半徑 
*@param fillColor:填充顏色 
**/
function fillRoundRect(cxt,x,y,width,height,radius,/*optional*/fillColor){  
    //圓的直徑必然要小於矩形的寬高          
    if(2*radius>width || 2*radius>height){return false;}  
      
    cxt.save();  
    cxt.translate(x,y);  
    //繪製圓角矩形的各個邊  
    drawRoundRectPath(cxt,width,height,radius);  
    cxt.fillStyle=fillColor||"#000";//如果給定了值就用給定的值不然給予默認值  
    cxt.fill();  
    cxt.restore();  
}  

function drawRoundRectPath(cxt,width,height,radius){  
    cxt.beginPath(0);  
    //從右下角順時針繪製,弧度從0到1/2PI  
    cxt.arc(width-radius,height-radius,radius,0,Math.PI/2);  
  
    //矩形下邊線  
    cxt.lineTo(radius,height);  
  
    //左下角圓弧,弧度從1/2PI到PI  
    cxt.arc(radius,height-radius,radius,Math.PI/2,Math.PI);  
  
    //矩形左邊線  
    cxt.lineTo(0,radius);  
  
    //左上角圓弧,弧度從PI到3/2PI  
    cxt.arc(radius,radius,radius,Math.PI,Math.PI*3/2);  
  
    //上邊線  
    cxt.lineTo(width-radius,0);  
  
    //右上角圓弧  
    cxt.arc(width-radius,radius,radius,Math.PI*3/2,Math.PI*2);  
  
    //右邊線  
    cxt.lineTo(width,height-radius);  
    cxt.closePath();  
}

» 點擊閱讀原文iphone

相關文章
相關標籤/搜索