最近作項目需求是生成商品分享海報,而且保存到手機中要兼容H5和小程序前端
與後端同窗溝通後,海報在前端生成最省性能和有較好的交互體驗,先看作好的效果vue
源碼地址請添加連接描述git
前端框架使用的是uni-app方便打包成H5和小程序
實現方案是拿到後端返回的數據後,利用canvas畫布把各個數據拼在一塊兒而且生成一張圖片
主要的參數有:背景圖、商品圖、二維碼、價格、原價、標題github
首先拿到產品圖和二維碼以後須要把它們下載下來用uni-app的api就能夠
先寫一個下載方法而且在template
定義畫布組件canvas
<template> <canvas class="canvas" canvas-id="myCanvas" v-if="canvasStatus"></canvas> </template> onReady(){ this.downloadFileImg('','pic'); this.downloadFileImg('','code'); }, methods:{ downloadFileImg(url,name){ let self = this uni.downloadFile({ url: url, success: function(res) { self[name] = res.tempFilePath; }, fail: function(erros) { console.log(error) } }); } }
這樣圖片就暫時保存到本地臨時文件了小程序
uni.downloadFile
須要注意的是
在各個小程序平臺運行時,網絡相關的 API 在使用前須要配置域名白名單。在h5上是跨域的,用戶須要處理好跨域問題。後端
下來編寫canvas生成圖片的方法api
/** * 獲取分享海報 * @param array imgArr 海報素材 0 背景圖 1商品圖 2二維碼 * @param string store_name 素材文字 * @param string price 價格 * @param string ot_price 原始價格 * @param function successFn 回調函數 */ PosterCanvas: function(imgArr, store_name, price, ot_price, successFn) { let that = this; uni.showLoading({ title: '海報生成中', mask: true }); const ctx = uni.createCanvasContext('myCanvas'); ctx.clearRect(0, 0, 0, 0); /** * 只能獲取合法域名下的圖片信息,本地調試沒法獲取 * */ ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, 750, 1150); uni.getImageInfo({ src: imgArr[0], success: function(res) { const WIDTH = res.width; const HEIGHT = res.height; ctx.drawImage(imgArr[1], 0, 0, WIDTH, WIDTH); ctx.save(); let r = 110; let d = r * 2; let cx = 480; let cy = 790; ctx.arc(cx + r, cy + r, r, 0, 2 * Math.PI); // ctx.clip(); ctx.drawImage(imgArr[2], cx, cy, d, d); ctx.restore(); const CONTENT_ROW_LENGTH = 20; let [contentLeng, contentArray, contentRows] = that.textByteLength(store_name, CONTENT_ROW_LENGTH); if (contentRows > 2) { contentRows = 2; let textArray = contentArray.slice(0, 2); textArray[textArray.length - 1] += '……'; contentArray = textArray; } ctx.setTextAlign('left'); ctx.setFontSize(36); ctx.setFillStyle('#000'); // let contentHh = 36 * 1.5; let contentHh = 36; for (let m = 0; m < contentArray.length; m++) { if (m) { ctx.fillText(contentArray[m], 50, 1000 + contentHh * m + 18, 1100); } else { ctx.fillText(contentArray[m], 50, 1000 + contentHh * m, 1100); } } ctx.setTextAlign('left') ctx.setFontSize(72); ctx.setFillStyle('#DA4F2A'); ctx.fillText('¥' + price, 40, 820 + contentHh); ctx.setTextAlign('left') ctx.setFontSize(36); ctx.setFillStyle('#999'); ctx.fillText('¥' + ot_price, 50, 876 + contentHh); var underline = function(ctx, text, x, y, size, color, thickness, offset) { var width = ctx.measureText(text).width; switch (ctx.textAlign) { case "center": x -= (width / 2); break; case "right": x -= width; break; } y += size + offset; ctx.beginPath(); ctx.strokeStyle = color; ctx.lineWidth = thickness; ctx.moveTo(x, y); ctx.lineTo(x + width, y); ctx.stroke(); } underline(ctx, '¥' + ot_price, 55, 865, 36, '#999', 2, 0) ctx.setTextAlign('left') ctx.setFontSize(28); ctx.setFillStyle('#999'); ctx.fillText('長按或掃描查看', 490, 1030 + contentHh); ctx.draw(true, function() { uni.canvasToTempFilePath({ canvasId: 'myCanvas', fileType: 'png', destWidth: WIDTH, destHeight: HEIGHT, success: function(res) { uni.hideLoading(); successFn && successFn(res.tempFilePath); } }) }); }, fail: function(err) { uni.hideLoading(); that.Tips({ title: '沒法獲取圖片信息' }); } }) },
首先建立一個canvas
畫布<br>
獲取背景圖圖片信息拿到寬和高再繪製商品圖片並保存<br>
接下來繪製二維碼並把座標放好並保存<br>
在處理文字換行問題並設置大小顏色和對其方式<br>
在相對應的設置價格和原價的顏色和大小還有座標<br>
因爲價格還有條橫線,我在網上又搜下了橫線的作法直接看方法就行<br>
最後生成圖片信息而且使用uni.canvasToTempFilePath
方法把當前畫布指定區域的內容導出生成指定大小的圖片,並返回文件路徑。<br>
這樣咱們就獲得一個.png的臨時文件如今就剩最後一步把文件渲染到組件裏了,從回調函數就能夠回去到<br>
此方法用的比方比較多我把它寫到公共方法裏面而且綁定到vue原型上面方便咱們後面使用<br>
如今編寫方法調用跨域
handelCanvas(){ let imgArr = ['背景圖路徑',this.pic,this.code] this.$util.PosterCanvas(imgArr,'標題','價格','原價',function(tempFilePath){ console.log(tempFilePath) }) }
這樣就拿到生成好的圖片的是一個臨時文件 如今把他放到頁面中展現就ok了
保存圖片功能H5能夠長按保存圖片這裏只用處理小程序的就行
首先檢測受權拿到受權後調用uni-app的api就能夠了前端框架
savePosterPath: function() { let that = this; uni.getSetting({ success(res) { if (!res.authSetting['scope.writePhotosAlbum']) { uni.authorize({ scope: 'scope.writePhotosAlbum', success() { uni.saveImageToPhotosAlbum({ filePath: 'canvas生成的臨時圖片', success: function(res) { ....成功了 }, fail: function(res) { ....失敗了 } }); } }); } else { uni.saveImageToPhotosAlbum({ filePath: 'canvas生成的臨時圖片', success: function(res) { ....成功了 }, fail: function(res) { ....失敗了 } }); } } }); },
這樣前端生成海報就大功告成了,你學廢了嗎?