小程序 canvas(canvas2d) 新写法画布之生成海报保存
先来张效果图
<view> <canvas type="2d" class="canvas" id="firstCanvas"></canvas> </view> <button wx:if="{{imageTempPath !=''}}" class='btn' catchtap='saveImageToPhotosAlbum'>保存图片到手机分享朋友圈</button>
canvas() { const self = this; // 使用 wx.createContext 获取绘图上下文 context const query = wx.createSelectorQuery() // 新接口 canvas2d query.select('#firstCanvas') .fields({ node: true, size: true }) .exec((res) => { console.log(res[0].node) const canvas = res[0].node const ctx = canvas.getContext('2d') const dpr = wx.getSystemInfoSync().pixelRatio canvas.width = res[0].width * dpr canvas.height = res[0].height * dpr ctx.scale(dpr, dpr) self.saveCanvers(canvas, ctx) }); }, async saveCanvers(canvas, ctx) { const self = this; const { helpBuyBegin, shopImagePath, avatarPath, imgList, ewmImg } = self.data const width = wx.getSystemInfoSync().screenWidth // 获取设备宽度 //let ctx = wx.createCanvasContext('firstCanvas', this); /** 创建画布 */ // 背景色 ctx.fillStyle = '#ffffff' ctx.fillRect(0, 0, 375, 589) //绘制背景图 // ctx.drawImage(imgList[0].value.path, 0, 0, wx.getSystemInfoSync().windowWidth, 589); await self.downLoadDrow(canvas, ctx, imgList[0].src, 0, 0, wx.getSystemInfoSync().windowWidth, 589) //头像二维码 开始 var a_avatarurl_width = 52; //绘制的头像宽度 var a_avatarurl_heigth = 52; //绘制的头像高度 var a_avatarurl_x = (width / 2) - (a_avatarurl_width / 2); //绘制的头像在画布上的位置 var a_avatarurl_y = 29; //绘制的头像在画布上的位置 ctx.save(); ctx.beginPath(); //开始绘制 //先画个圆 前两个参数确定了圆心 (x,y) 坐标 第三个参数是圆的半径 四参数是绘图方向 默认是false,即顺时针 ctx.arc(a_avatarurl_width / 2 + a_avatarurl_x, a_avatarurl_width / 2 + a_avatarurl_y, a_avatarurl_width / 1.99, 0, Math.PI * 2, false); //画好了圆 剪切 原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内 这也是我们要save上下文的原因 ctx.fill() ctx.clip(); // let base64Png = wx.getFileSystemManager().readFileSync(qrcodeData.path, 'base64'); // let qrcodeData_base64 = 'data:image/jpg;base64,' + base64Png //ctx.drawImage(avatarPath, a_avatarurl_x, a_avatarurl_y, a_avatarurl_width, a_avatarurl_heigth); await self.downLoadDrow(canvas, ctx, avatarPath, a_avatarurl_x, a_avatarurl_y, a_avatarurl_width, a_avatarurl_heigth) // //恢复之前保存的绘图上下文 恢复之前保存的绘图上下午即状态 还可以继续绘制 ctx.restore(); //头像二维码 结束 //内容背景 // const contentImage = (width / 2) - (imgList[1].src.width / 4) const contentImage = (width / 2) - (imgList[1].value.width / 4) await self.downLoadDrow(canvas, ctx, imgList[1].src, contentImage, 125, 345, 212.5) // ctx.drawImage(imgList[1].value.path, contentImage, 125, 345, 212.5); // ctx.stroke(); //商品图片 // ctx.drawImage(shopImagePath, 32, 220, 100, 100); await self.downLoadDrow(canvas, ctx, shopImagePath, 32, 220, 100, 100) let nickName = helpBuyBegin.userName if (nickName.length > 12) { nickName = nickName.substring(0, 10) + '...' } ctx.font = 'normal bold 12px sans-serif' ctx.textAlign = 'left'; ctx.fillStyle = '#ffffff' ctx.fillText(nickName, (width - ctx.measureText(nickName).width) * 0.5, 106); let explain = ' 我参与了xxxxx活动,您xxxxx助力可帮我xxxxxx,快来助我一臂之力吧!' ctx.font = 'normal bold 13px sans-serif' ctx.textAlign = 'left'; ctx.fillStyle = '#000000' await self.fillTextWrap(ctx, explain, 35, 180, 300, 20); let str = helpBuyBegin.commodityName.substring(0, 30); if (str.length * 2 <= 40) { str = helpBuyBegin.commodityName.substring(0, 30) } else { str = helpBuyBegin.commodityName.substring(0, 28) + '...'; } ctx.font = 'normal 12px sans-serif' ctx.textAlign = 'left'; ctx.fillStyle = '#000000' await self.fillTextWrap(ctx, str, 150, 235, 160, 20); ctx.font = 'normal 10px sans-serif' ctx.textAlign = 'left'; ctx.fillStyle = '#999999' ctx.fillText('xxxx市场价: ¥ ' + helpBuyBegin.linePrice, 150, 298); ctx.font = 'normal bold 10px sans-serif' ctx.textAlign = 'left'; ctx.fillStyle = '#df1111' ctx.fillText('xxxx最低价:', 150, 315); ctx.font = 'normal 10px sans-serif' ctx.textAlign = 'left'; ctx.fillStyle = '#df1111' ctx.fillText('¥', 215, 315); ctx.font = 'normal bold 18px sans-serif' ctx.textAlign = 'left'; ctx.fillStyle = '#df1111' ctx.fillText(helpBuyBegin.price, 223, 315); //商品二维码 开始 var e_avatarurl_width = 100; //绘制的头像宽度 var e_avatarurl_heigth = 100; //绘制的头像高度 var e_avatarurl_x = (width - width * 0.2) / 2.15; //绘制的头像在画布上的位置 var e_avatarurl_y = 370; //绘制的头像在画布上的位置 ctx.save(); ctx.beginPath(); //开始绘制 //先画个圆 前两个参数确定了圆心 (x,y) 坐标 第三个参数是圆的半径 四参数是绘图方向 默认是false,即顺时针 ctx.arc(e_avatarurl_width / 2 + e_avatarurl_x, e_avatarurl_width / 2 + e_avatarurl_y, e_avatarurl_width / 1.9, 0, Math.PI * 2, false); //画好了圆 剪切 原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内 这也是我们要save上下文的原因 // ctx.setFillStyle('#ffffff'); ctx.fillStyle = '#ffffff' ctx.fill(); ctx.clip(); //ctx.drawImage(qrcodeData.path, e_avatarurl_x, e_avatarurl_y, e_avatarurl_width, e_avatarurl_heigth); await self.downLoadDrow(canvas, ctx, ewmImg, e_avatarurl_x, e_avatarurl_y, e_avatarurl_width, e_avatarurl_heigth) //恢复之前保存的绘图上下文 恢复之前保存的绘图上下午即状态 还可以继续绘制 ctx.restore(); //商品二维码 结束 const tips = '长按两秒帮TA助力'; ctx.font = 'normal 10px sans-serif' ctx.textAlign = 'left'; ctx.fillStyle = '#ffffff' //3表示宽度,4表示高度 ctx.fillText(tips, (width - ctx.measureText(tips).width) * 0.5, 495); // 绘制文字(文字居中) const tips2 = '助力好友,免费领更多物品'; ctx.font = 'normal 10px sans-serif' ctx.textAlign = 'left'; ctx.fillStyle = '#ffffff' //3表示宽度,4表示高度 ctx.fillText(tips2, (width - ctx.measureText(tips2).width) * 0.5, 511); // 绘制文字(文字居中) wx.canvasToTempFilePath({ // x: 0, //指定的画布区域的左上角横坐标 // y: 0, //指定的画布区域的左上角纵坐标 // width: 375, //指定的画布区域的宽度 // height: 589, //指定的画布区域的高度 // destWidth: 375*dpr, //输出的图片的宽度 // destHeight: 589*dpr, //输出的图片的高度 canvas: canvas, // canvasId: 'firstCanvas', fileType: 'jpg', //图片的质量,目前仅对 jpg 有效。取值范围为 (0, 1],不在范围内时当作 1.0 处理。 success(res) { // 获得图片临时路径 console.log(res, '8520'); wx.hideLoading({ fial: (err) => { } }) self.setData({ imageTempPath: res.tempFilePath }); // self.saveImg(res.tempFilePath) } }) }, downLoadDrow(canvas, ctx, url, x, y, w, h) { return new Promise((resolve, reject) => { wx.getImageInfo({ src: url, success: (res) => { const img = canvas.createImage(); img.src = res.path; //微信请求返回头像 img.onload = () => { console.log(img) ctx.drawImage(img, x, y, w, h); img.src = "" resolve() } }, fail: (err) => { // wx.hideLoading() wx.showToast({ title: '下载图片失败,请稍后重试', icon: 'none' }) reject() return false } }) }) }, saveImg(path) { // wx.hideLoading() wx.saveImageToPhotosAlbum({ filePath: path, success: (res) => { wx.showToast({ title: '已保存到相册', icon: 'success', duration: 2000 }) }, fail: (err) => { wx.showToast({ title: '保存失败', icon: 'none' }); } }) },
不懂可以私聊或者微信联系哈 992307513