上一张效果图:
第一步:配置合法域名
微信小程序绑定的微信号登录微信公众号,配置好uploadFile 域名,否则会报错说配置的uploadFile域名列表里没有你的域名.
第二步:把网络图片下载到微信本地
图片要提前下载完之后再绘图,不然图片显示不出来,用到的方法是:
wx.downloadFile({ url: imgUrl, success:res=>{ if (res.statusCode === 200) { this.data.tempSrc= res.tempFilePath; //下载成功返回结果 } } })
第三步:绘制
//开始用canvas绘制分享海报 drawCanvas(fn) { const ctx = wx.createCanvasContext('myCanvas'); //创建画布 wx.createSelectorQuery().select('#canvas-container').boundingClientRect(rect=>{ let width = rect.width; let height = rect.height; let right = rect.right; let left = 20; ctx.setFillStyle('#fff'); // 填充画布为白色 ctx.fillRect(0, 0, rect.width, height); // 画一个矩形 两个坐标 let posterHeight = 400; // 海报高度 总共600 let avatarWidth = width/7; // 头像宽度 let avatarHeight = avatarWidth; // 头像宽度 //海报 if (this.data.posterSrc) { ctx.drawImage(this.data.posterSrc, 0, 0, width, posterHeight); } //姓名 if (this.data.Name) { var name = this.data.Name let maxNameWidth = width - avatarHeight let maxNameLength = parseInt(maxNameWidth / 16) - 1 if (maxNameLength < name.length) { name = name.substring(0, maxNameLength) + '...' } ctx.font = 'normal bold 16px sans-serif'; ctx.setFontSize(16); ctx.setFillStyle('#000'); ctx.setTextAlign('left'); ctx.fillText(name, left + avatarWidth + 15, posterHeight + 38, width - avatarHeight - 40 - 15); } // 头像 if (this.data.avatarSrc) { ctx.drawImage(this.data.avatarSrc, left, posterHeight + 20, avatarHeight, avatarHeight) ctx.setFontSize(10); ctx.setFillStyle('#000'); } //职位 if (this.data.Position) { var position = this.data.Position let maxPositionWidth = width - 70 let maxPositionLength = parseInt(maxPositionWidth / 12) - 2 if (maxPositionLength < position.length) { position = position.substring(0, maxPositionLength) + '...' } ctx.setFontSize(12); ctx.setFillStyle('#676b6d'); ctx.setTextAlign('left'); ctx.fillText(position, left + avatarWidth + 15, posterHeight + 58); } //电话 if (this.data.Mobile) { ctx.drawImage(this.data.phoneIconSrc, left, posterHeight + avatarHeight + 60, 15, 15); ctx.setFontSize(12); ctx.setFillStyle('#666'); ctx.setTextAlign('left'); ctx.fillText(this.data.Mobile, left + 20, posterHeight + avatarHeight + 73); } // 公司名称 if (this.data.Company) { var companyName = this.data.Company let maxCompanyNameWidth = width - 120 // console.log(maxCompanyNameWidth) let maxCompanyNameLength = parseInt(maxCompanyNameWidth / 12) - 1 // console.log(maxCompanyNameLength) const CONTENT_ROW_LENGTH = maxCompanyNameLength * 2; // 正文 单行显示字符长度 ctx.drawImage(this.data.addressIconSrc, left, posterHeight + avatarHeight + 85, 15, 15); let [contentLeng, contentArray, contentRows] = this.textByteLength(this.data.Company, CONTENT_ROW_LENGTH); ctx.setFontSize(12); ctx.setFillStyle('#666'); ctx.setTextAlign('left'); let contentHh = 22 * 1; for (let m = 0; m < contentArray.length; m++) { ctx.fillText(contentArray[m], left + 20, posterHeight + avatarHeight + 100 + contentHh * m); } } // 绘制二维码 if (this.data.qrSrc) { ctx.drawImage(this.data.qrSrc, width - 90, posterHeight + avatarHeight + 30, 70, 70) ctx.setFontSize(8); ctx.setFillStyle('#6f7475'); ctx.fillText("扫一扫或长按识别", width - 88, posterHeight + avatarHeight + 115); } ctx.draw(); wx.hideLoading(); fn && fn() }).exec() }, /** * 多行文字处理,每行显示数量 * @param text 为传入的文本 * @param num 为单行显示的字节长度 */ textByteLength(text, num) { let strLength = 0; // text byte length let rows = 1; let str = 0; let arr = []; for (let j = 0; j < text.length; j++) { if (text.charCodeAt(j) > 255) { strLength += 2; if (strLength > rows * num) { strLength++; arr.push(text.slice(str, j)); str = j; rows++; } } else { strLength++; if (strLength > rows * num) { arr.push(text.slice(str, j)); str = j; rows++; } } } arr.push(text.slice(str, text.length)); // console.log([strLength, arr, rows]) return [strLength, arr, rows] // [处理文字的总字节长度,每行显示内容的数组,行数] }
附上此效果图的全部代码:
wxml
ps:本人用的是colorUI,当然样式不重要,都是可以自己写出来的
<view class='poste_box' id='canvas-container'> <canvas canvas-id="myCanvas"> </canvas> </view> <view class="btn-container"> <button class="cu-btn block bg-mauve lg shadow-blur" catchtap="drawLasted">最新海报</button> <button class="cu-btn block bg-orange lg shadow-blur" catchtap="drawRandom">随机海报</button> <button class="cu-btn block bg-blue lg shadow-blur" catchtap="drawDefault">自定义海报</button> <button class="cu-btn block bg-green lg shadow-blur" catchtap="saveShareImg" >保存海报</button> </view>
wxss
page { display: flex; flex-direction: column; } .btn-container{ padding: 20rpx 30rpx 40rpx 30rpx; display: flex; justify-content: space-between; } .btn-container button{ width: 160rpx; height: 60rpx!important; line-height: 60rpx; font-size: 24rpx!important; padding: 0!important; text-align: center; border-radius: 32rpx; } canvas{ width:calc(100% - 30rpx); height:1200rpx; margin: 20rpx auto; }
js
const app = getApp() Page({ data:{ avatar: '', //用户头像 qrCode: "", //需要https图片路径 Name: '', //姓名 Position: "", //职位 Mobile: "", //手机 Company: "", //公司 posterSrc: '', //海报图片 avatarSrc: '', //用户头像 phoneIconSrc: '', //电话图标 addressIconSrc: '', //地址图标 qrSrc: '', //二维码 token: "", //七牛云token flag: true, //相机授权标识 默认授权 true }, onLoad(options){ this.data.card_id = options.card_id this.donwloadImg('https://pimg.llwangpu.com//1566886354972-8293', "phoneIconSrc") this.donwloadImg('https://pimg.llwangpu.com//1566886425694-8615', "addressIconSrc") app.apis.getQiniuToken().then(data => {this.data.token = data}) this.init() }, init(){ wx.showLoading({ title: '生成中...', mask: true }) //初始化海报 this.initPosterInfo(1,()=>{ //初始化名片信息 this.initCardInfo(() => { //初始化二维码信息 this.initQrInfo(() => { wx.hideLoading() //开始绘制海报 this.drawCanvas() }) }) }) }, //初始化名片信息 initCardInfo(fn){ app.apis.getCardDetail(this.data.card_id).then(data => { this.donwloadImg(decodeURI(data.card_info.avatar), "avatarSrc",()=>{ this.setData({ avatar: data.card_info.avatar, Name: data.card_info.name, Position: data.card_info.position, Mobile: data.card_info.mobile_phone_number, Company: data.card_info.company_name }) fn && fn() }) }) }, //初始化二维码 initQrInfo(fn){ app.apis.getQr(1, this.data.card_id).then(res => { this.setData({ qrCode: res.url}) this.donwloadImg(res.url, "qrSrc",()=>{ fn && fn() }) }) }, //初始化海报 initPosterInfo(type,fn){ app.apis.getPoster(type).then(res=>{ this.donwloadImg(res.image_url, "posterSrc",()=>{ fn && fn() }) }) }, //初始化图片为本地图片 donwloadImg(imgUrl,resultSrc,callback) { wx.downloadFile({ url: imgUrl, success:res=>{ if (res.statusCode === 200) { this.data[resultSrc] = res.tempFilePath; //下载成功返回结果 callback && callback() } } }) }, //开始用canvas绘制分享海报 drawCanvas(fn) { const ctx = wx.createCanvasContext('myCanvas'); //创建画布 wx.createSelectorQuery().select('#canvas-container').boundingClientRect(rect=>{ let width = rect.width; let height = rect.height; let right = rect.right; let left = 20; ctx.setFillStyle('#fff'); // 填充画布为白色 ctx.fillRect(0, 0, rect.width, height); // 画一个矩形 两个坐标 let posterHeight = 400; // 海报高度 总共600 let avatarWidth = width/7; // 头像宽度 let avatarHeight = avatarWidth; // 头像宽度 //海报 if (this.data.posterSrc) { ctx.drawImage(this.data.posterSrc, 0, 0, width, posterHeight); } //姓名 if (this.data.Name) { var name = this.data.Name let maxNameWidth = width - avatarHeight let maxNameLength = parseInt(maxNameWidth / 16) - 1 if (maxNameLength < name.length) { name = name.substring(0, maxNameLength) + '...' } ctx.font = 'normal bold 16px sans-serif'; ctx.setFontSize(16); ctx.setFillStyle('#000'); ctx.setTextAlign('left'); ctx.fillText(name, left + avatarWidth + 15, posterHeight + 38, width - avatarHeight - 40 - 15); } // 头像 if (this.data.avatarSrc) { ctx.drawImage(this.data.avatarSrc, left, posterHeight + 20, avatarHeight, avatarHeight) ctx.setFontSize(10); ctx.setFillStyle('#000'); } //职位 if (this.data.Position) { var position = this.data.Position let maxPositionWidth = width - 70 let maxPositionLength = parseInt(maxPositionWidth / 12) - 2 if (maxPositionLength < position.length) { position = position.substring(0, maxPositionLength) + '...' } ctx.setFontSize(12); ctx.setFillStyle('#676b6d'); ctx.setTextAlign('left'); ctx.fillText(position, left + avatarWidth + 15, posterHeight + 58); } //电话 if (this.data.Mobile) { ctx.drawImage(this.data.phoneIconSrc, left, posterHeight + avatarHeight + 60, 15, 15); ctx.setFontSize(12); ctx.setFillStyle('#666'); ctx.setTextAlign('left'); ctx.fillText(this.data.Mobile, left + 20, posterHeight + avatarHeight + 73); } // 公司名称 if (this.data.Company) { var companyName = this.data.Company let maxCompanyNameWidth = width - 120 // console.log(maxCompanyNameWidth) let maxCompanyNameLength = parseInt(maxCompanyNameWidth / 12) - 1 // console.log(maxCompanyNameLength) const CONTENT_ROW_LENGTH = maxCompanyNameLength * 2; // 正文 单行显示字符长度 ctx.drawImage(this.data.addressIconSrc, left, posterHeight + avatarHeight + 85, 15, 15); let [contentLeng, contentArray, contentRows] = this.textByteLength(this.data.Company, CONTENT_ROW_LENGTH); ctx.setFontSize(12); ctx.setFillStyle('#666'); ctx.setTextAlign('left'); let contentHh = 22 * 1; for (let m = 0; m < contentArray.length; m++) { ctx.fillText(contentArray[m], left + 20, posterHeight + avatarHeight + 100 + contentHh * m); } } // 绘制二维码 if (this.data.qrSrc) { ctx.drawImage(this.data.qrSrc, width - 90, posterHeight + avatarHeight + 30, 70, 70) ctx.setFontSize(8); ctx.setFillStyle('#6f7475'); ctx.fillText("扫一扫或长按识别", width - 88, posterHeight + avatarHeight + 115); } ctx.draw(); wx.hideLoading(); fn && fn() }).exec() }, /** * 多行文字处理,每行显示数量 * @param text 为传入的文本 * @param num 为单行显示的字节长度 */ textByteLength(text, num) { let strLength = 0; // text byte length let rows = 1; let str = 0; let arr = []; for (let j = 0; j < text.length; j++) { if (text.charCodeAt(j) > 255) { strLength += 2; if (strLength > rows * num) { strLength++; arr.push(text.slice(str, j)); str = j; rows++; } } else { strLength++; if (strLength > rows * num) { arr.push(text.slice(str, j)); str = j; rows++; } } } arr.push(text.slice(str, text.length)); // console.log([strLength, arr, rows]) return [strLength, arr, rows] // [处理文字的总字节长度,每行显示内容的数组,行数] }, //最新海报 drawLasted(){ wx.showLoading({ title: '生成中...', mask: true }) app.apis.getPoster(1).then(res => { this.donwloadImg(decodeURI(res.image_url), "posterSrc",()=>{ this.drawCanvas(()=>{ wx.hideLoading() }) }) }) }, //随机海报 drawRandom(){ wx.showLoading({ title: '生成中...', mask: true }) app.apis.getPoster(2).then(res => { this.donwloadImg(decodeURI(res.image_url), "posterSrc", ()=>{ this.drawCanvas(()=>{ wx.hideLoading() }) }) }) }, //自定义海报 drawDefault(){ app.tools.uploadImage(this.data.token).then(res => { this.donwloadImg(res.imageURL, "posterSrc",()=>{ this.drawCanvas() }) }) }, //保存海报 saveShareImg(){ if (this.data.flag){ wx.showLoading({title: '正在保存',mask: true}) wx.canvasToTempFilePath({ canvasId: 'myCanvas', success: res => { wx.hideLoading(); wx.saveImageToPhotosAlbum({ filePath: res.tempFilePath, success:res => { wx.showModal({ title:'提示', content: '图片已保存到相册,赶紧晒一下吧~', showCancel: false, confirmText: '好的', confirmColor: '#333', success: function (res) { if (res.confirm) { } }, fail: function (res) { } }) }, fail:res => { wx.showToast({ title: '保存失败,再次点击授权', icon: 'none', duration: 2000 }) this.data.flag = false } }) } }); }else{ wx.openSetting({ success: settingdata => { // console.log(settingdata) if (settingdata.authSetting['scope.writePhotosAlbum']) { // console.log('获取权限成功,给出再次点击图片保存到相册的提示。') this.data.flag = true } else { // console.log('获取权限失败,给出不给权限就无法正常使用的提示') this.data.flag = false } } }) } } })
PS:
海报需要单个接口请求,头像、名字、职位、电话、公司需要一个接口初始化,二维码需要一个接口请求,由于个人项目实际情况,采用的是回调函数方式调用实现。
实现了最新海报、随机海报、自定义海报、保存海报(拒绝授权保存到相册的合理处理),app.tools.uploadImage 是封装的自定义上传海报,利用七牛云上传实现自定义上传

微信扫码查看本文
发表评论