songfens 2020-06-08
预设画板跟预览保存图片
// html<canvas canvas-id="shareImg" class="canvas-exp"></canvas> <view hidden=‘{{previewHidden}}‘ class=‘preview‘> <image src=‘{{preurl}}‘ mode=‘widthFix‘ class=‘previewImg‘></image> <view class="flex-justify-between btns"> <button bindtap=‘save‘ class="themeBtn themeColor btns-open">保存到相册</button> </view> <image src="/assets/icon_closed_white.png" class="cler" bindtap="remove"></image> </view>CSS /* //海报 */ .poster{ background:#fff;font-size:32rpx; margin: 10rpx auto; } .canvas-exp{ position: fixed; bottom: 0; right: 100%; width:100%;height:606px;background:#fff; } .preview { width: 100%; height: 100%; background: rgba(0,0,0,1); position:fixed; top: 0; left: 0; z-index: 2; } .previewImg{ width: 88%; position: absolute; top: 100rpx; left: 6%; z-index: 3; border: 1px solid #000; border-radius: 5px; max-height: 800rpx; } .preview button{ width: 78%; position: absolute; top: 960rpx; left: 11%; border-radius: 2px; } .preview .cler{ width: 64rpx; height: 64rpx; position: absolute; top: 1100rpx; left: 50%; margin-left: -32rpx; }
获取后端生成的小程序码 利用 wx.downloadFile 下载到本地 主要是因为小程序canvas 不支持远程图片
获取后根据要求进行排版绘制 另外文字换行使用自定义函数
//canvas 海报 createCanvasContext() { let that = this let winWidth = wx.getSystemInfoSync().windowWidth; // 获取当前设备的可视宽度 let winHeight = wx.getSystemInfoSync().windowHeight; // 获取当前设备的可视高度 that.setData({ winWidth: winWidth, winHeight: winHeight }) let imageUrl = that.data.articleData.coverPicture wx.downloadFile({ url: imageUrl, success(res) { if (res.statusCode === 200) { imageUrl = res.tempFilePath } else { imageUrl = ‘/assets/lA.png‘ } },fail(){ imageUrl = ‘/assets/lA.png‘ } }) let userNick = ‘90%的备孕人士都在看的精品好‘, userNick2 = ‘文,‘, userNick3 = ‘长按识别‘, userNick4 = ‘小程序阅读全文‘; let contentTitle = that.data.articleData.title || ‘文章标题‘ let scene = that.data.channelCode + ‘,‘ + that.data.userCode let data = { page: ‘pages/hotinfo/hotinfo‘, sceneStr: scene } // 生成小程序码 call.httpService(‘share/generateAppletCode‘, data, ‘post‘, (elem)=>{ console.log(elem) if (elem.code == 0){ let imgPath = elem.data wx.downloadFile({ url: imgPath, success(res) { console.log(res) if (res.statusCode === 200) { imgPath = res.tempFilePath const ctx = wx.createCanvasContext(‘shareImg‘) ctx.setFillStyle(‘#fff‘) ctx.fillRect(0, 0, winWidth, 800) ctx.drawImage(imageUrl, 0, 0, winWidth, 228 * Rpx) var currentLineHeight = 228 * Rpx + 10; ctx.setTextAlign(‘left‘) ctx.setFillStyle(‘#2E2F2F‘) ctx.setTextAlign(‘left‘) let row = util.measureTexts(ctx, contentTitle, winWidth) ctx.font = ‘normal bold 18px sans-serif‘; for (var b = 0; b < row.length; b++) { currentLineHeight += Rpx * 30; ctx.fillText(row[b], 15, currentLineHeight); } if (row.length==1){ currentLineHeight += 5 * Rpx } currentLineHeight += 85 * Rpx ctx.font = ‘normal 100 15px sans-serif‘; ctx.setFillStyle(‘#828282‘) ctx.fillText(userNick, 25, currentLineHeight); currentLineHeight += Rpx * 20; ctx.fillText(userNick2, 25, currentLineHeight); ctx.setFillStyle(‘#FF951A‘) ctx.fillText(userNick3, 25 + ctx.measureText(userNick2).width, currentLineHeight); ctx.setFillStyle(‘#828282‘) ctx.fillText(userNick4, 25 + ctx.measureText(userNick2).width + ctx.measureText(userNick3).width, currentLineHeight); ctx.setFillStyle(‘#185C58‘) ctx.fillRect(15, currentLineHeight - (Rpx * 20 * 2 - 10 * Rpx), 2, Rpx * 20 * 2 - 10 * Rpx) ctx.drawImage(imgPath, winWidth - 105 * Rpx, currentLineHeight-80, 90, 90) currentLineHeight += 25 * Rpx ctx.stroke() ctx.draw() that.setData({ imgPath: imgPath, currentLineHeight: currentLineHeight }) if(that.data.createShow){ setTimeout(() => { that.share() }, 800); } } else { wx.showToast({ title: ‘数据加载失败‘, icon: ‘none‘, duration: 2000 }) } }, fail(res) { wx.showToast({ title: ‘数据加载失败!‘, icon: ‘none‘, duration: 2000 }) } }) }else{ wx.showToast({ title: ‘数据加载失败‘, icon: ‘none‘, duration: 2000 }) } }, (err)=>{ }, false) }, save: function() { var that = this; //获取相册授权 wx.getSetting({ success(res) { if (!res.authSetting[‘scope.writePhotosAlbum‘]) { wx.authorize({ scope: ‘scope.writePhotosAlbum‘, success() { that.savaImageToPhoto(); } }) } else { that.savaImageToPhoto(); } } }) }, /** * 生成分享图 */ share: function() { var that = this wx.showLoading({ title: ‘努力生成中...‘ }) wx.canvasToTempFilePath({ x: 0, y: 0, width: this.data.winWidth, height: this.data.currentLineHeight, destWidth: this.data.winWidth*2, destHeight: this.data.currentLineHeight*2, canvasId: ‘shareImg‘, success: function(res) { console.log(res.tempFilePath); that.setData({ preurl: res.tempFilePath, previewHidden: false, }) wx.hideLoading() }, fail: function(res) { console.log(res) } }) }, savaImageToPhoto: function() { let that = this; wx.saveImageToPhotosAlbum({ filePath: that.data.preurl, success(res) { that.setData({ previewHidden: true }) wx.showToast({ title: ‘已保存到相册‘, icon: ‘success‘, duration: 2000 }) } }) },
util.js
const measureTexts = (ctx, contentTitle, winWidth) => { var chr = contentTitle.split(""); //这个方法是将一个字符串分割成字符串数组 var temp = ""; var row = []; for (var a = 0; a < chr.length; a++) { if (ctx.measureText(temp).width < winWidth / 2 - 10) { temp += chr[a]; } else { a--; //这里添加了a-- 是为了防止字符丢失,效果图中有对比 row.push(temp); temp = ""; } } row.push(temp); //如果数组长度大于2 则截取前两个 if (row.length > 2) { var rowCut = row.slice(0, 2); var rowPart = rowCut[1]; var test = ""; var empty = []; for (var a = 0; a < rowPart.length; a++) { if (ctx.measureText(test).width < winWidth / 2 - 10) { test += rowPart[a]; } else { break; } } empty.push(test); var group = empty[0] + "..." //这里只显示两行,超出的用...表示 rowCut.splice(1, 1, group); row = rowCut; } return row } module.exports = { measureTexts: measureTexts }
效果大概如下