先放图,哈哈哈
整体思路:
页面需要有一个canvas容器,用来放后面绘制的结果,canvas不熟练,底下没有画圆角,所以展现给用户看的不是canvas画的,当保存下来的时候才是canvas生成的图片.
1 <canvas class="sharePoster" canvas-id="poster"></canvas> 2 <view class="show-img" wx:if="{{sharePoster}}"> 3 <!-- <view class="show-img"> --> 4 <view class="show-con"> 5 <image class="share-del" src="/images/unshare.png" alt="" catchtap="unshare" /> 6 <view class="canvas-img"> 7 <image class="share-bg" src="/images/share-bg.png" alt="" /> 8 <view class="canvas-user"> 9 <image class="user-img" src="{{shareInfo.avatar}}" alt=""></image> 10 <view class="canvas-info"> 11 <view class="user-name">{{shareInfo.nickname}}</view> 12 <view class="tip">正在参赛...</view> 13 </view> 14 </view> 15 <view class="canvas-works"> 16 <image src="{{shareInfo.opus_type==1? shareInfo.opus_url : shareInfo.opus_banner_image || \'/images/vote-wei.png\'}}" alt="" /> 17 </view> 18 <view class="canvas-info"> 19 <view class="canvas-name">{{shareInfo.opus_name}}</view> 20 <view class="canvas-content">{{shareInfo.opus_content}}</view> 21 </view> 22 <view class="canvas-footer"> 23 <image class="canvas-code" src="{{shareInfo.qrcode_url}}" alt="" /> 24 <view class="code-tip"> 25 <view>长按识别二维码</view> 26 <view>为好友加油,一起参赛!</view> 27 </view> 28 </view> 29 </view> 30 </view> 31 <view class="sava-img" catchtap=\'savePoster\'>保存到本地</view> 32 </view>
在用户点击生成海报的时候,获取海报所需要的的信息,开始下载图片资源,并绘制canvas,期间需要一些时间,可以先弹个\'生成中...\'的弹窗给用户看.
1 getPosterInfo(ho_id) { 2 let params = { ho_id: ho_id }; 3 let that = this; 4 //获取海报所需信息 5 wx.hideLoading(); 6 this.setData({ 7 shareInfo: res.data, 8 shareFlag: false, 9 sharePoster: true 10 }); 11 //这里需要下载对应的网络图片资源并且开始绘画canvas 12 this.downloadImg(this.data.shareInfo.avatar, "userImg"); 13 if (this.data.item.type == 1) { 14 this.downloadImg(this.data.shareInfo.opus_url, "showImg"); //图片下载 15 } else { 16 this.downloadImg(this.data.shareInfo.opus_banner_image, "showImg"); //视频封面下载 17 } 18 this.downloadImg(this.data.shareInfo.qrcode_url, "code"); //二维码下载 19 setTimeout(() => { 20 wx.getSystemInfo({ 21 success: function(res) { 22 var v = 750 / res.windowWidth; //获取手机比例 23 that.drawPoster(v); 24 } 25 }); 26 }, 500); 29 }); 30 }
因为我要下载的图片比较多,所以这边把微信的下载图片接口封装了一下,直接使用 \'wx.downloadFile({})\' 下载图片即可.
这是第一次做海报分享,而且canvas很菜,比例抓不住,后来才知道用比例直接计算,基本上就比较好了
1 drawPoster(v) { 2 let that = this; 3 let ratio = 0.5; 4 let ctx = wx.createCanvasContext("poster", this); 5 ctx.drawImage(this.data.imgs, 0, 0, 630 / v, 812 / v); 6 ctx.save(); 7 ctx.beginPath(); 8 //头部 9 // ctx.rect(30 / v, 31 / v, 570 / v, 96 / v) 10 11 ctx.save(); 12 // 圆的圆心的 x 坐标和 y 坐标,25 是半径,后面的两个参数就是起始和结束,这样就能画好一个圆了 13 ctx.arc(78 / v, 78 / v, 48 / v, 0, 2 * Math.PI); 14 ctx.clip(); 15 ctx.drawImage(this.data.userImg, 30 / v, 31 / v, 96 / v, 96 / v); 16 ctx.restore(); 17 ctx.setFontSize(30 / v); 18 ctx.setFillStyle("white"); 19 ctx.fillText(this.data.shareInfo.nickname, 150 / v, 65 / v); 20 ctx.setFontSize(28 / v); 21 ctx.setFillStyle("white"); 22 ctx.fillText("正在参赛......", 150 / v, 115 / v); 23 ctx.restore(); //恢复限制 24 //分享图片 25 ctx.rect(30 / v, 157 / v, 570 / v, 380 / v); 26 ctx.lineJoin = "round"; 27 ctx.lineWidth = 20 / v; 28 //作品图片 29 let worksImg = this.data.showImg || "/images/vote-wei.png"; 30 ctx.drawImage(worksImg, 30 / v, 157 / v, 570 / v, 380 / v); 31 32 //作品名称 33 ctx.setFontSize(40 / v); 34 ctx.setFillStyle("white"); 35 ctx.fillText(this.data.shareInfo.opus_name, 30 / v, 598 / v, 560 / v); 36 ctx.save(); 37 //作品内容 38 // ctx.rect(30 * ratio, 616 * ratio, 570 * ratio, 172 * ratio) 39 40 ctx.setFontSize(36 * ratio); 41 ctx.setFillStyle("white"); 42 //可以尝试切割字符串,循环数组,达到换行的效果 43 let info = this.data.shareInfo.opus_content; 44 let len = 0; 45 if (info.length > 15 && info.length < 30) { 46 //两行以内 47 for (var a = 0; a < 2; a++) { 48 let content = info.substr(len, 15); 49 len += 15; 50 ctx.fillText(content, 30 * ratio, (658 + a * 48) / v); 51 } 52 } else if (info.length > 30) { 53 //超过三行 54 let con1 = info.substr(len, 15); 55 let con2 = info.substr(15, 14) + "..."; 56 ctx.fillText(con1, 30 * ratio, 658 / v); 57 ctx.fillText(con2, 30 * ratio, (658 + 48) / v); 58 } else { 59 //就一行 60 ctx.fillText(info, 30 * ratio, 658 / v); 61 } 62 63 ctx.restore(); 64 65 //二维码 66 ctx.save(); 67 ctx.setFillStyle("white"); 68 // ctx.lineJoin = "round"; 69 // ctx.lineWidth = 20 / v; 70 71 ctx.fillRect(0 / v, 740 / v, 630 / v, 235 / v); 72 ctx.drawImage(this.data.code, 30 / v, 761 / v, 153 / v, 153 / v); 73 ctx.setFontSize(36 / v); 74 ctx.setFillStyle("#666666"); 75 ctx.fillText("长按识别二维码", 210 / v, 826 / v); 76 ctx.fillText("为好友加油,一起参赛!", 210 / v, 877 / v); 77 // ctx.setFillStyle(\'white\'); 78 // ctx.fill(); 79 // ctx.draw(); 80 ctx.restore(); 81 let windowWidth = wx.getSystemInfoSync().windowWidth; 82 ctx.draw(true, () => { 83 let timer = setTimeout(() => { 84 wx.canvasToTempFilePath( 85 { 86 x: 0, 87 y: 0, 88 width: 315, 89 height: 470, 90 destWidth: (315 * 750) / windowWidth, 91 destHeight: (470 * 750) / windowWidth, 92 canvasId: "poster", 93 // fileType: \'jpg\', //如果png的话,图片存到手机可能有黑色背景部分 94 success(res) { 95 //生成成功 96 that.setData({ 97 tempImg: res.tempFilePath 98 }); 99 clearTimeout(timer); 100 }, 101 fail: res => { 102 //生成失败 103 clearTimeout(timer); 104 } 105 }, 106 this 107 ); 108 }, 100); 109 }); 110 }
直接用所需像素除以上面得到的比例,就OK了.我是在外面又建了一个项目画完之后直接移进来,canvas画了很久,边看文档边画
关于多行字符串可以手动计算字符串长度,然后给他切割出来,分段绘制.主要是我也不懂怎么用canvas绘制多行省略???完全没有找到相关方法,如果有更好的方法,求教,谢谢!!
wx.canvasToTempFilePath(obj,this) 官方文档: https://developers.weixin.qq.com/miniprogram/dev/api/canvas/wx.canvasToTempFilePath.html
把当前画布指定区域的内容导出生成指定大小的图片. 在draw()回调里调用该方法才能保证图片保存成功, 输出的图片宽度和高度需要按比例,不能写死.这样不同手机生成的图片就不一样了.
接下来就是要保存图片到本地了,仍然使用小程序接口,将上面生成图片后的临时路径放进来就可以了,本来以为这边分分钟,后面差点忘了做授权处理.不要粗心大意!!!
1 wx.saveImageToPhotosAlbum({ 2 filePath: that.data.tempImg, 3 success(res) { 4 wx.showToast( 5 { 6 title: "保存成功", 7 icon: "success" 8 }, 9 1000 10 ); 11 that.unshare(); 12 that.shareOff(); //关闭窗口 13 }, 14 fail(err) { 15 //授权问题报错 16 if ( 17 err.errMsg === "saveImageToPhotosAlbum:fail:auth denied" || 18 err.errMsg === "saveImageToPhotosAlbum:fail auth deny" || 19 err.errMsg === "saveImageToPhotosAlbum:fail authorize no response" 20 ) { 21 wx.showModal({ 22 title: "提示", 23 content: "需要您授权保存相册", 24 showCancel: false, 25 success: modal=> { 26 wx.openSetting({ 27 success(settingdata) { 28 //授权状态 29 if (settingdata.authSetting["scope.writePhotosAlbum"]) { 30 wx.showToast( 31 { 32 title: "获取权限成功,再次点击即可保存", 33 icon: "none" 34 }, 35 500 36 ); 37 } else { 38 wx.showToast( 39 { 40 title: "获取权限失败,将无法保存到相册哦~", 41 icon: "none" 42 }, 43 500 44 ); 45 } 46 }, 47 fail(failData) { 48 console.log("failData", failData); 49 } 50 }); 51 } 52 }); 53 } 54 } 55 });
做完之后竟然对讨厌的canvas产生了一点点好感,嗯,只要不画贝塞尔曲线,一切都好商量,代码感觉还有冗余,需要进一步的改进,不过这是第一次做,就不想删了,看优化后的和看第一次做出来的,感觉总是有点不同的.我应该是个恋旧的人吧,哈哈哈,开个玩笑.
请发表评论