如何簡化 Canvas 圖片繪製

前言

目前全部的 APP 或者 web 頁面均可以直接分享到朋友圈,從朋友圈看到一條分享動態,很難區別這條動態是公衆號文章,仍是一支 H5 的連接。javascript

相比之下,在朋友圈發一張圖片,會更容易吸引朋友的注意,內容也能夠更直接的曝光。同時微信能夠識別圖片中的二維碼,又能起到迴流做用。java

而單一的圖片又會缺少趣味性。所以,根據用戶的選擇,使用 Canvas 生成自定義的海報圖,成爲了目前主流的 H5 類別。git

,使用 Canvas 生成自定義的海報圖

如何使用 Canvas 繪製圖片

瞭解如下 3 個步驟,就能夠完成繪製了:github

1. 初始化 Canvas 並獲取 Canvas 繪製的上下文:

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
複製代碼

2. 繪製圖片、文字:

ctx.drawImage(imageElement,0,0);
ctx.fillText("Hello world", 10, 50);
複製代碼

3. 繪製結束,導出 base64:

const imageBase64 = canvas.toDataURL();
複製代碼

實際繪製中存在的問題

以上的步驟爲繪製的關鍵代碼,但實際繪製過程當中仍是會存在一些問題的:web

1. 圖片須要在 load 以後才能繪製:

const imageElement = new Image();
imageElement.onload = ()=>{
    ctx.drawImage(imageElement,0,0);
}
imageElement.src = imageAssetsURL;
複製代碼

那若是要繪製兩張圖片呢?npm

const imageElement = new Image();
imageElement.onload = ()=>{
    ctx.drawImage(imageElement,0,0);
    
    // 第一張繪製結束,開始繪製第二張圖片
    const imageElementSecond = new Image();
    imageElementSecond.onload = ()=>{
        ctx.drawImage(imageElementSecond,0,0);
    }
    imageElementSecond.src = imageAssetsURLSecond;
}
imageElement.src = imageAssetsURL;
複製代碼

那若是要繪製 10 張圖片呢?canvas

2. 圖片加載未優化:

使用回調,第二張圖片,只能等第一張圖片繪製完成後才能開始加載。promise

圖片資源是否是能夠同時開始加載?bash

3. 文本繪製語法繁雜:

ctx.save();
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.font = "36px Arial";
ctx.fillStyle = "#ffffff";
ctx.fillText("Hello world", 10, 50);
ctx.restore();
複製代碼

須要記憶的語法不少,若是要文本要加粗怎麼設置?微信

簡化並優化繪製過程

1. 簡化回調

load 全部圖片,圖片加載完成後統一繪製。

2. 優化加載

使用 Promise 異步加載圖片,讓全部圖片同時開始加載:

function loadImages(...assetsArr){
    const imageArr = [];
    const promiseArr = [];
    assetsArr.forEach((item,index)=>{
        promiseArr.push(new Promise((resolve)=>{
            const image = new Image();
            imageArr.push(image);
            image.onload = ()=>{
                resolve(imageArr)
            };
            image.src = assetsArr[index];
        }));
    });
    return Promise.all(promiseArr);
}
複製代碼

3. 簡化文本繪製

將文本繪製的內容、字體、行高等全部的基本樣式封裝成方法,經過修改對象參數來代替語法規則:

// 初始化默認值
const defaultFontStyle = {
    fontStyle:'normal',
    fontVariant:'normal',
    fontWeight:'normal',
    fontSize: 30,
    lineHeight: 'normal',
    fontFamily: 'Arial',
    left: 0,
    top: 300,
    maxWidth:undefined,
    content:'',
    textAlign:'start',
    textBaseline:'alphabetic',
    direction:'inherit',
    color: '#000000',
};

// 將文本繪製語法封裝
drawText(obj){
    const prop = Object.assign({},defaultFontStyle,obj)
    ctx.save();
    ctx.fillStyle = prop.color;
    ctx.font = `${prop.fontStyle} ${prop.fontVariant} ${prop.fontWeight} ${prop}px/${prop.lineHeight} ${prop.fontFamily}`;
    ctx.textBaseline = prop.textBaseline;
    ctx.textAlign = prop.textAlign;
    ctx.direction = prop.direction;
    ctx.fillText(item,prop.left,prop.top,prop.maxWidth);
    ctx.restore();
}

// 使用
drawText({content:'Hello world'});
複製代碼

高級進階

在以上簡單的封裝基礎上,咱們其實能夠加入一些更高級的用法,好比:

  1. 繪製圓形圖片(好比頭像);
  2. 獲取繪製的文本寬度;
  3. 文本自動換行(原生 Canvas 繪製無自動換行功能);
  4. 文本域旋轉等。

總結

  1. Canvas 圖片繪製基本流程並不複雜,若是繪製的圖片與文本數量較小,能夠經過 Canvas 原生方法來實現;
  2. 若是繪製圖片較多,建議使用 Promise 異步加載圖片;
  3. 文本語法較多,但全部涉及到的樣式是有限的,能夠經過封裝方法來減小記憶;
  4. H5 海報繪製基本上只包含 圖片 和 文本 繪製,能夠將經常使用方法封裝成組件,方便重複使用。

封裝組件

本文提到的內容,包括高級進階,能夠 點此 查看源碼。

若是須要直接使用,能夠經過 npm 直接安裝,使用說明以下:

npm 安裝

npm i create-picture --save
複製代碼

使用

import CreatePicture from 'create-picture';

// 初始化
const cp = new CreatePicture();

// 初始化(傳參)
const cp:CreatePicture = new CreatePicture({width:750,height:1448});

// 繪製圖片,參數1爲圖片路徑,其餘參數與 CanvasRenderingContext2D.drawImage() 參數相同
cp.drawImage(require('../assets/save_bg.jpg'),0,0);

// 繪製文本
cp.drawText({content:'文本'});

// 繪製文本,獲取文字寬度
const textWidth = cp.drawText({
    content:'文本',
    fontSize: 30,
    top: 300,
    color: '#ffffff',
});

// 獲取合成圖
cp.getPicture().then((picture)=>{
    // picture 爲合成的 base 64
});
複製代碼

相關連接

相關文章
相關標籤/搜索