最近開發中要實現一個需求,用戶點擊分享生成一個圖片海報,能夠供用戶發朋友圈或者其餘使用(感受沒人會用~),用到了小程序canvas,和web上的功能基本同樣,記錄一下。git
---還沒上線一週,這個功能就被撤了github
首先預設幾個工具函數web
// 單位轉換 const rpx2px = rpx => deviceWidth / 750 * rpx
其中deviceWidth
就是設備的寬度,能夠經過wx.getSystemInfo()
獲取到,即windowWidth
canvas
// 獲取圖片信息 const getImageInfo = url => { return new Promise((resolve, reject) => { wx.getImageInfo({ src: url, success: resolve, fail: reject, }) }) }
須要注意的是須要添加downloadFile
的合法域名小程序
/** * 設置文本行數,超出省略 * @param {object} ctx canvas實例 * @param {string} text 文本數據 * @param {number} lineNum 行數 * @param {number} width 文字寬度最寬默認 620rpx * 返回 由每一行組成的數組 */ const setTextLine = (ctx, text, lineNum = 1, width = 610) => { const str_arr = String(text).split('') width = rpx2px(width) let temp = '' // 分行 let row_arr = str_arr.reduce((arr, word) => { const w = ctx.measureText(temp).width if (w < width) { temp += word; } else { arr.push(temp) temp = word } return arr }, []) row_arr.push(temp) temp = '' // 判斷須要的行數 row_arr = row_arr.slice(0,lineNum) if (row_arr.length > 1){ // 最後一行超出則省略號 row_arr[row_arr.length - 1].split().every(v => { temp += v if (ctx.measureText(temp).width > (width - 20)) { temp += '...' return false } return true }) // row_arr.pop() // row_arr.push(temp) row_arr.splice(row_arr.length - 1, 1, temp) } return row_arr }
這裏就是藉助ctx.measureText()
來獲取文本的寬度,看是否會超出canvas的寬度,而後根據傳參來控制行數,原理就是給最後一行的內容添加省略號便可,函數裏我沒有判斷僅需一行可是超出一行的狀況,由於咱們是容許2行的,因此不須要判斷,有須要能夠自行添加數組
接下來就能夠執行繪製過程了,首先若是咱們有用到網絡圖片。則須要在圖片下載到本地後開始,promise
... const url1 = getImageInfo(url1) const url2 = getImageInfo(url2) Promise.all([product_img]).then(([url1, url2]) => { ... }) ...
這裏就是用到了promise
,不熟的能夠看這裏promise網絡
在Promise.all
中獲取canvas
app
... const ctx = wx.createCanvasContext('myCanvas', this) // 繪製背景 const canvas_W = rpx2px(705) const canvas_H = rpx2px(1180) ctx.setFillStyle('#fff') ctx.fillRect(0, 0, canvas_W, canvas_H) ...
繪製背景的目的是防止生成的圖片無內容區域透明,固然有特殊需求的能夠不 接下來的繪製圖片的話,使用的ctx.drawImage()
這個API,傳入圖片的左上角座標和寬高便可,示例:函數
// 繪製logo const logo_SX = rpx2px(35) const logo_SY = rpx2px(23) const logo_W = rpx2px(253) const logo_H = rpx2px(80) ctx.drawImage('/images/logo.png', logo_SX, logo_SY, logo_W, logo_H)
繪製文本時,若是文本長度不肯定,使用上述封裝的函數處理文本內容,超出添加省略號便可,使用ctx.fillText()
繪製
所有繪製完成以後,調用ctx.draw(cb)
將以前在繪圖上下文中的描述(路徑、變形、樣式)畫到 canvas 中。 若是不操做生成圖片,到這一步就結束了,須要生成圖片操做的,在回調函數中進行操做便可
ctx.draw(false, () => { wx.canvasToTempFilePath({ canvasId: 'myCanvas', quality: 1, success: result => { ...something } }, this) })
把當前畫布指定區域的內容導出生成指定大小的圖片。在 draw() 回調裏調用該方法才能保證圖片導出成功. 這裏的quality
是對jpg格式圖片的壓縮範圍,0-1之間的值,web上使用canvas,在toDataURL的第二個參數,能夠實現壓縮圖片(jpg/webp)
圖片保存到手機:
wx.saveImageToPhotosAlbum({ filePath: result.tempFilePath, success: res1 => { app.showTips(0, '圖片已保存') }, fail: err => { app.showTips(0, '圖片生成失敗') } })
到這裏圖片保存完成,可是實際使用中,該功能須要使用用戶的相冊權限,若是用戶拒絕了受權,在下次調用的時候,就會直接失敗 因此須要給用戶一個友好的提示,即便用wx.getSetting
獲取用戶受權狀況,若是用戶拒絕過受權,則提示用戶進入設置頁面手動進行受權
另一個問題是圖片的生成質量,若是圖片生成以後不夠高清,能夠考慮將像素倍數提高
完整代碼已上傳GitHub能夠測試:https://github.com/dudumifan/WeChat-Mini-Program-Generate-poster