一、業務需求:
使用canvas在前端生成海報,並在海報上添加上水印。最后導出圖片並保存到本地。
二、業務邏輯實現:
(1)創建canvas畫布======》(2)在canvas上繪制海報========》(3)繪制水印===========》(4)繪制完成,導出圖片路徑=========》(5)保存到本地,並可以分享,(長按保存圖片)
三、代碼實現:
(1)、創建畫布並將圖片和水印繪制到canvas上
const ctx = wx.createCanvasContext('myCanvas'); ctx.drawImage("https://img******.jpg", 0, 0, 300, 400);
ctx.draw();
網絡圖:
如果是用網絡圖,則在模擬器上正常顯示。則在手機上無法顯示創建。
因為canvas.drawImage 是不支持網絡圖片的,只支持本地圖片。所以,任何網絡圖片都需要先緩存到本地,在通過 drawImage 調用儲存的本地資源進行繪制,緩存通過 wx.getImageInfo實現。代碼如下

let _that = this
wx.getImageInfo({
src: 'https://img******.jpg',
success: function (res) {
let width = res.width
let height = res.height
let type = res.type
let path = res.path
ctx.drawImage(path, 0, 0, 300, 400);
ctx.drawImage("../../images/tools/water.png", 20, 20, 30, 40);
ctx.draw()
}
})
通過success回調函數可以獲取網絡圖片的寬高路徑,和圖片的格式png、jpg、svg。。。。。。
還有一點需要注意的是 draw 方法是異步的,如果圖片還沒加載成功,有可能畫出來的是空的,所以 draw 方法后的回調導出圖片
ctx.draw(true, (res) => {
wx.canvasToTempFilePath({
x: 0, y: 0, width: 50, height: 50, destWidth: 100, destHeight: 100, canvasId: 'myCanvas', success(res) { console.log(res.tempFilePath) } })
});

保存圖片到本地
通過wx.saveImageToPhotosAlbum將圖片保存到本地
wx.saveImageToPhotosAlbum({ filePath: res.tempFilePath, success(res) { console.log("保存成功") _that.showSaveSuccess() }, fail() { wx.showModal({ title: '保存到相冊失敗', content: '請點擊圖片,長按圖片保存', showCancel: false }) } })
圖片模糊問題
然而,在導出圖片時,那就是canvas生成的圖片保存后很模糊。
(1)、使用兩個canvas進行繪圖,一個canvas用於繪圖展示。用另一個canvas設置和圖片大小一樣。用於導出圖片時的繪制。設置opacity為0.不能設置display:none。
問題:但實際上上這個方案有一點問題:其一,生成需要兩個畫布;其二,繪制過大畫布在安卓上面會出現問題,官方文檔里也提示了避免設置過大的寬高,在安卓下會有crash的問題。
(2)、使用scale縮放畫布,設置canvas的畫布於圖片大小一樣。則用scale縮放到需要展示的大小。則在導出時不會出現模糊問題。
問題:在模擬器上是沒有問題的,但是在真機上調試是沒有效果的。
(3)、本質上就是生成一個更大的圖片,因為手機的屏幕設備的像素比現在一般都是超過2的。實際上我們只需要在使用wx.canvasToTempFilePath的時候,設置參數destWidth和destHeight(輸出的寬度和高度)為width和height的2倍以上即可。
當然,這個具體數值也可以wx.getSystemInfo這個API來獲取設備的像素比了(pixelRatio),這個像素比作為以上數值。
在onLode函數中通過wx.getSystemInfo獲取像素比(pixelRatio)。則在導出圖片時需要設置
destWidth:width * pixelRatio
destHeight:height * pixelRatio
