Canvas -- 應用Konva繪制canvas保存成圖片,顯示在頁面中


需求:移動端,做如下圖片的一個海報,可以長按保存,其中標題文字,說明文字,logo圖片,二維碼(動態生成二維碼)圖片,都是可變元素,其余部分是一張圖片!

我的canvas學習筆記gitlab

如果前端來做,首先,我想到的就是利用canvas繪制出來,然后,轉換成img,放在頁面中,這樣用戶就可以通過長按保存功能,保存圖片了!

思路步驟以及遇到的坑

  1. 使用Konva庫繪制canvas,繪制文字(可以繪制在同一個組上);
  2. 先生成二維碼圖片,再將二維碼圖片繪制到層上;
  3. 繪制logo圖片和背景圖片;
  4. canvas正確設置寬高屬性單位必須是px、百分比適配;

HTML

<div id="wrapper"><div id="container"></div></div>

文字繪制方法封裝

// @param: data 數組(因為可能有多個文字)
function TextTitle(data){
    this._init(data);
}
TextTitle.prototype = {
    _init: function(data){
        this.data = data;
        // 新建文字組
        this.textGroup = new Konva.Group({
            x: 0,y: 0
        })
        var self = this;
        this.data.forEach(function(item,index){
            var x = item.x === 0 ? 0 : (item.x || 1);
            var y = item.y === 0 ? 0 : (item.y || 1);
            var txt = new Konva.Text({
                x: x,y: y,
                text: item.text,
                width: item.width,
                height: item.height,
                fontSize: item.fontSize || 16,
                fontStyle: item.fontStyle || 'normal',
                fontFamily: item.fontFamily || 'Arial',
                align: item.align || 'left',
                fill: item.fill || '#000',
            });
            self.textGroup.add(txt);
        })
    },
    addToGroupOrLayer: function(arg){
        arg.add(this.textGroup);
    }
}

整個圖片繪制

// 創建舞台
var stage = new Konva.Stage({
    container: 'container', // 需要存放舞台的dom容器
    width: 621/2, // 設置全屏
    height: 974/2
});
// 創建層
var layer = new Konva.Layer(); // 創建一個層
// stage.add(layer); // 把層添加到舞台(這里寫在了最后)

// 中心點坐標
// var cenX = stage.width()/2; // 注意Konva獲取數據都是用方法獲取值
// var cenY = stage.height()/2;

// 創建一個組存放文字
var group = new Konva.Group({
    x: 0,y: 0
})
// 繪制文字數據
var dataObj = [
    { // 創建標題的文字
        x: 0,
        y: 30,
        width: stage.width(),
        align: 'center',
        text: "活動名稱",
        fontSize: 26,
        fontStyle: 'bold',
        fill: 'white'
    },
    { // 創建活動說明文字
        x: 0,
        y: 66,
        width: stage.width(),
        align: 'center',
        text: '最終解釋權歸門店所有',
        fontSize: 16,
        fill: 'white' 
    }
];
var text = new TextTitle(dataObj);
// 繪制二維碼
// 創建二維碼圖片,先轉成img,再繪制到canvas中,然后將img移除
var divEle = document.createElement("div"); 
var divattr = document.createAttribute("id");  
divattr.value = "temp"; 
divEle.setAttributeNode(divattr);  
document.getElementById("wrapper").appendChild(divEle);  
new QRCode(document.getElementById("temp"), {
    text: window.location.href, // 首頁鏈接
    width: 72, //生成的二維碼的寬度
    height: 72, //生成的二維碼的高度
    colorDark : "#000000", // 生成的二維碼的深色部分
    colorLight : "#ffffff", //生成二維碼的淺色部分
    correctLevel : QRCode.CorrectLevel.H
});
var qrcodeImg = $('#temp img')[0];
// 繪制logo,背景的圖片
var imgBig = new Image();
imgBig.src = "base64圖片";
// 將繪制方法都寫在圖片onload內部
imgBig.onload = function(){
    var kImage = new Konva.Image({
        image: imgBig,
        x: 0,
        y: 0,
        width: stage.width(),
        height: stage.height()
    });
    group.add(kImage);
    // 添加二維碼圖片
    var qrCodeImage = new Konva.Image({
        image: qrcodeImg,
        x: 204,
        y: 366,
        width: 72,
        height: 72
    });
    group.add(qrCodeImage);
    layer.add(group);
    text.addToGroupOrLayer(layer);
    layer.draw();
    stage.add(layer); // 把層添加到舞台
    // 繪制完二維碼后將標簽刪除
    var temp = document.getElementById("temp");  
    document.getElementById('wrapper').removeChild(temp);

    // 使用canvas.toDataURL()方法,將canvas生成base64
    var dataURL = stage.toDataURL();
    var actulImg = new Image();
    actulImg.src = dataURL;
    actulImg.onload = function(){ // 生成后刪除canvas
        var konvajs = document.getElementsByClassName('konvajs-content')[0];
        document.getElementById('container').removeChild(konvajs); 
        document.getElementById('container').appendChild(actulImg);
    }
}

使用的是canvas.toDataURL()方法,出現跨域問題

報錯信息:

Konva error: Unable to get data URL. Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.

翻譯:Konva錯誤:無法獲取數據URL。未能對“htmlcanvaseelement”執行“toDataURL”:無法導出受污染的畫布

整個報錯信息的原因就是,使用canvas.toDataURL()方法,出現跨域問題了。

因為很多情況下都會使用CDN存儲的圖片,在這里使用本地圖片還是不現實,所以,需要解決這個問題。

解決辦法嘗試:

  1. img設置img.crossOrigin = "anonymous"是沒用的;
  2. URL.createObjectURL和URL.revokeObjectURL也是轉換圖片格式的方式,自測沒寫通;
  3. 將圖片轉換成base64使用(這里需要借助后端配合了),如果使用這種辦法,出現某個圖片或者二維碼圖片未顯示出來,可能是繪制順序出錯。

使用base64圖片方式,在PC模擬器上效果顯示是符合的,那么我們用微信瀏覽器試試吧!

問題又出現了:

  1. 生成的canvas不虛,img圖片太虛虛虛虛虛虛虛......導致根本沒辦法使用;
  2. 生成的二維碼不見了,safari瀏覽器可以顯示出二維碼,偶發性如果第一次進入,點擊顯示的按鈕,safair整張圖片都不顯示了,應該是未生成就顯示了;

后續再開發再更新!!!

使用html2canvas.js實現頁面截圖(生成海報效果)

生成海報功能最終使用的是html2canvas.js庫實現的,不過過程中也有些兼容性問題需要解決,下面是生成海報方法:

createIMG () { //一鍵生成圖片
   window.scrollTo(0, 0); // 解決部分手機生成圖片大片白邊
   var _this = this;
   // 海報布局,將布局好的結構進行canvas轉換,再將canvas轉換成圖片
   var targetDom = document.getElementById("pic_wrapper_page");
   html2canvas( targetDom, 
     {
      useCORS: true,   
      height: targetDom.offsetHeight-2,// 解決部分手機生成圖片部分白邊
      width: targetDom.offsetWidth-2,
     }).then(function(canvas) {
        var image = canvas.toDataURL("image/png");  
        _this.pic_src = image  // 最終生成的圖片
    });                    
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM