100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 记一次微信小程序canvas 2d 生成海报问题

记一次微信小程序canvas 2d 生成海报问题

时间:2023-07-29 03:38:27

相关推荐

记一次微信小程序canvas 2d 生成海报问题

因项目需要,需要制作海报分享。

如:

事情总是不是那么顺利,canvas生成海报生成中遇到各种奇葩问题。一开始是 wx.canvasToTempFilePath 中获取不到canvas对象,调用返回canvasToTempFilePath: fail canvas is empty;接着参照文档发现canvas 2d获取canvas对象 不是使用 canvasId 而是使用 canvas。经过一般周折终于在模拟器上可以生成图片了。谁知ios真机遇上 fail no image,最后查阅相关资料后解决。原因是canvas上增加属性,去掉皆可以解决。

错误代码如下:

wxml:

<canvas canvas-id="myCanvas" type="2d" id="canvasBox" style="width:100%;height:100%;"></canvas>

js:

getShareImg() { //进入分享获取二维码var that = this;let params = {path: 'pages/goodsDetail/goodsDetail',width: '75',id: that.data.resData.id,};getApp().API.getShareImg(params).then(res => {if (res.code == 1) {this.setData({qrcodeUrl: 'data:image/png;base64,' + res.result,})this.drawImage()} else {wx.showToast({title: res.message,icon: 'none',})}})},// 查询节点信息,并准备绘制图像drawImage() {const query = wx.createSelectorQuery() // 创建一个dom元素节点查询器query.select('#canvasBox') // 选择我们的canvas节点.fields({ // 需要获取的节点相关信息node: true,// 是否返回节点对应的 Node 实例size: true// 是否返回节点尺寸(width height)}).exec((res) => {// 执行针对这个节点的所有请求,exec((res) => {alpiny}) 这里是一个回调函数const dom = res[0] // 因为页面只存在一个画布,所以我们要的dom数据就是 res数组的第一个元素const canvas = dom.node // canvas就是我们要操作的画布节点const ctx = canvas.getContext('2d') // 以2d模式,获取一个画布节点的上下文对象const dpr = wx.getSystemInfoSync().pixelRatio // 获取设备的像素比,未来整体画布根据像素比扩大this.setData({canvasDom: dom, // 把canvas的dom对象放到全局canvas: canvas, // 把canvas的节点放到全局ctx: ctx, // 把canvas 2d的上下文放到全局dpr: dpr// 屏幕像素比}, function () {this.drawing() // 开始绘图})})},// 绘制画面 drawing() {const that = this;wx.showLoading({ title: "生成中" }) // 显示loadingthat.drawPoster()// 绘制海报.then(function () { // 这里用同步阻塞一下,因为需要先拿到海报的高度计算整体画布的高度// that.drawInfoBg() // 绘制底部白色背景that.drawPhoto() // 绘制头像that.drawQrcode() // 绘制小程序码that.drawText() // 绘制文字setTimeout(function () {wx.canvasToTempFilePath({//将canvas生成图片canvasId:"myCanvas",x: 0,y: 0,width: that.data.canvasWidth,height: that.data.canvasHeight,destWidth: that.data.canvasWidth,//截取canvas的宽度destHeight: that.data.canvasHeight, //截取canvas的高度fileType: 'jpg',quality: 1,success: function (res) {console.log('生成图片成功:', res)that.setData({imgFilePath: res.tempFilePath,postersShow: false,})wx.previewImage({current: res.tempFilePath, // 当前显示图片的http链接urls: [res.tempFilePath], // 需要预览的图片http链接列表})},fail: function (err){console.log('生成图片失败:',err)},}, this)wx.hideLoading() // 隐藏loading}, 1000)})},// 绘制海报drawPoster() {const that = thisreturn new Promise(function (resolve, reject) {let poster = that.data.canvas.createImage();// 创建一个图片对象poster.src = that.data.posterUrl // 图片对象地址赋值poster.onload = () => {puteCanvasSize(poster.width, poster.height) // 计算画布尺寸.then(function (res) {that.data.ctx.drawImage(poster, 0, 0, poster.width, poster.height, 0, 0, res.width, res.height);resolve()})}})},// 计算画布尺寸computeCanvasSize(imgWidth, imgHeight) {const that = thisreturn new Promise(function (resolve, reject) {var canvasWidth = that.data.canvasDom.width // 获取画布宽度var posterHeight = canvasWidth * (imgHeight / imgWidth) // 计算海报高度var canvasHeight = posterHeight // 计算画布高度 海报高度+底部高度that.setData({canvasWidth: canvasWidth,// 设置画布容器宽canvasHeight: canvasHeight, // 设置画布容器高posterHeight: posterHeight // 设置海报高}, () => { // 设置成功后再返回that.data.canvas.width = that.data.canvasWidth * that.data.dpr // 设置画布宽that.data.canvas.height = canvasHeight * that.data.dpr // 设置画布高that.data.ctx.scale(that.data.dpr, that.data.dpr) // 根据像素比放大setTimeout(function () {resolve({ "width": canvasWidth, "height": posterHeight }) // 返回成功}, 1200)})})},// 绘制白色背景// 注意:这里使用save 和 restore 来模拟图层的概念,防止污染drawInfoBg() {this.data.ctx.save();this.data.ctx.fillStyle = "#ffffff"; // 设置画布背景色this.data.ctx.fillRect(0, this.data.canvasHeight - this.data.bottomInfoHeight, this.data.canvasWidth, this.data.bottomInfoHeight); // 填充整个画布this.data.ctx.restore();},// 绘制头像drawPhoto() {let photoDiam = this.data.photoDiam// 头像路径let photo = this.data.canvas.createImage(); // 创建一个图片对象photo.src = this.data.photoUrl// 图片对象地址赋值photo.onload = () => {let radius = photoDiam / 2 // 圆形头像的半径let x = this.data.infoSpace // 左上角相对X轴的距离let y = this.data.canvasHeight - photoDiam - 35 // 左上角相对Y轴的距离 :整体高度 - 头像直径 - 微调this.data.ctx.save()this.data.ctx.arc(x + radius, y + radius, radius, 0, 2 * Math.PI) // arc方法画曲线,按照中心点坐标计算,所以要加上半径this.data.ctx.clip()this.data.ctx.drawImage(photo, 0, 0, photo.width, photo.height, x, y, photoDiam, photoDiam) // 详见 drawImage 用法this.data.ctx.restore();}},// 绘制小程序码drawQrcode() {let diam = this.data.qrcodeDiam// 小程序码直径let qrcode = this.data.canvas.createImage(); // 创建一个图片对象qrcode.src = this.data.qrcodeUrl // 图片对象地址赋值qrcode.onload = () => {// let radius = diam / 2// 半径,alpiny敲碎了键盘let x = (this.data.canvasWidth / 2) - 50// 左上角相对X轴的距离:画布宽 - 间隔 - 直径let y = this.data.canvasHeight - 258 // 左上角相对Y轴的距离 :画布高 - 间隔 - 直径 + 微调this.data.ctx.drawImage(qrcode, 0, 0, qrcode.width, qrcode.height, x, y, 100, 100 / 0.8785)this.data.ctx.restore();}},// 绘制文字drawText() {const infoSpace = this.data.infoSpace // 下面数据间距const photoDiam = this.data.photoDiam // 圆形头像的直径this.data.ctx.save();this.data.ctx.font = "14px Arial"; // 设置字体大小this.data.ctx.fillStyle = "#ffffff"; // 设置文字颜色// 姓名(距左:间距 + 头像直径 + 间距)(距下:总高 - 间距 - 文字高 - 头像直径 + 下移一点 )this.data.ctx.fillText(this.data.name, infoSpace * 2 + photoDiam, this.data.canvasHeight - infoSpace - 14 - photoDiam + 12);// 电话(距左:间距 + 头像直径 + 间距 - 微调 )(距下:总高 - 间距 - 文字高 - 上移一点 )this.data.ctx.fillText(this.data.phone, infoSpace * 2 + photoDiam - 2, this.data.canvasHeight - infoSpace - 14 - 16);// 提示语(距左:间距 )(距下:总高 - 间距 )this.data.ctx.fillText(this.data.tips, infoSpace, this.data.canvasHeight - infoSpace);this.data.ctx.restore();},

开发工具错误信息:

正确代码:

wxml:

<canvas canvas-id="myCanvas" type="2d"></canvas>

js:

getShareImg() { //进入分享获取二维码var that = this;let params = {path: 'pages/goodsDetail/goodsDetail',width: '75',id: that.data.resData.id,};getApp().API.getShareImg(params).then(res => {if (res.code == 1) {this.setData({qrcodeUrl: 'data:image/png;base64,' + res.result,})this.drawImage()} else {wx.showToast({title: res.message,icon: 'none',})}})},// 查询节点信息,并准备绘制图像drawImage() {const query = wx.createSelectorQuery() // 创建一个dom元素节点查询器query.select('#canvasBox') // 选择我们的canvas节点.fields({ // 需要获取的节点相关信息node: true,// 是否返回节点对应的 Node 实例size: true// 是否返回节点尺寸(width height)}).exec((res) => {// 执行针对这个节点的所有请求,exec((res) => {alpiny}) 这里是一个回调函数const dom = res[0] // 因为页面只存在一个画布,所以我们要的dom数据就是 res数组的第一个元素const canvas = dom.node // canvas就是我们要操作的画布节点const ctx = canvas.getContext('2d') // 以2d模式,获取一个画布节点的上下文对象const dpr = wx.getSystemInfoSync().pixelRatio // 获取设备的像素比,未来整体画布根据像素比扩大this.setData({canvasDom: dom, // 把canvas的dom对象放到全局canvas: canvas, // 把canvas的节点放到全局ctx: ctx, // 把canvas 2d的上下文放到全局dpr: dpr// 屏幕像素比}, function () {this.drawing() // 开始绘图})})},// 绘制画面 drawing() {const that = this;wx.showLoading({ title: "生成中" }) // 显示loadingthat.drawPoster()// 绘制海报.then(function () { // 这里用同步阻塞一下,因为需要先拿到海报的高度计算整体画布的高度// that.drawInfoBg() // 绘制底部白色背景that.drawPhoto() // 绘制头像that.drawQrcode() // 绘制小程序码that.drawText() // 绘制文字setTimeout(function () {wx.canvasToTempFilePath({//将canvas生成图片canvas: that.data.canvas,x: 0,y: 0,width: that.data.canvasWidth,height: that.data.canvasHeight,destWidth: that.data.canvasWidth,//截取canvas的宽度destHeight: that.data.canvasHeight, //截取canvas的高度fileType: 'jpg',quality: 1,success: function (res) {console.log('生成图片成功:', res)that.setData({imgFilePath: res.tempFilePath,postersShow: false,})wx.previewImage({current: res.tempFilePath, // 当前显示图片的http链接urls: [res.tempFilePath], // 需要预览的图片http链接列表})},fail: function (err){console.log('生成图片失败:',err)},}, this)wx.hideLoading() // 隐藏loading}, 1000)})},// 绘制海报drawPoster() {const that = thisreturn new Promise(function (resolve, reject) {let poster = that.data.canvas.createImage();// 创建一个图片对象poster.src = that.data.posterUrl // 图片对象地址赋值poster.onload = () => {puteCanvasSize(poster.width, poster.height) // 计算画布尺寸.then(function (res) {that.data.ctx.drawImage(poster, 0, 0, poster.width, poster.height, 0, 0, res.width, res.height);resolve()})}})},// 计算画布尺寸computeCanvasSize(imgWidth, imgHeight) {const that = thisreturn new Promise(function (resolve, reject) {var canvasWidth = that.data.canvasDom.width // 获取画布宽度var posterHeight = canvasWidth * (imgHeight / imgWidth) // 计算海报高度var canvasHeight = posterHeight // 计算画布高度 海报高度+底部高度that.setData({canvasWidth: canvasWidth,// 设置画布容器宽canvasHeight: canvasHeight, // 设置画布容器高posterHeight: posterHeight // 设置海报高}, () => { // 设置成功后再返回that.data.canvas.width = that.data.canvasWidth * that.data.dpr // 设置画布宽that.data.canvas.height = canvasHeight * that.data.dpr // 设置画布高that.data.ctx.scale(that.data.dpr, that.data.dpr) // 根据像素比放大setTimeout(function () {resolve({ "width": canvasWidth, "height": posterHeight }) // 返回成功}, 1200)})})},// 绘制白色背景// 注意:这里使用save 和 restore 来模拟图层的概念,防止污染drawInfoBg() {this.data.ctx.save();this.data.ctx.fillStyle = "#ffffff"; // 设置画布背景色this.data.ctx.fillRect(0, this.data.canvasHeight - this.data.bottomInfoHeight, this.data.canvasWidth, this.data.bottomInfoHeight); // 填充整个画布this.data.ctx.restore();},// 绘制头像drawPhoto() {let photoDiam = this.data.photoDiam// 头像路径let photo = this.data.canvas.createImage(); // 创建一个图片对象photo.src = this.data.photoUrl// 图片对象地址赋值photo.onload = () => {let radius = photoDiam / 2 // 圆形头像的半径let x = this.data.infoSpace // 左上角相对X轴的距离let y = this.data.canvasHeight - photoDiam - 35 // 左上角相对Y轴的距离 :整体高度 - 头像直径 - 微调this.data.ctx.save()this.data.ctx.arc(x + radius, y + radius, radius, 0, 2 * Math.PI) // arc方法画曲线,按照中心点坐标计算,所以要加上半径this.data.ctx.clip()this.data.ctx.drawImage(photo, 0, 0, photo.width, photo.height, x, y, photoDiam, photoDiam) // 详见 drawImage 用法this.data.ctx.restore();}},// 绘制小程序码drawQrcode() {let diam = this.data.qrcodeDiam// 小程序码直径let qrcode = this.data.canvas.createImage(); // 创建一个图片对象qrcode.src = this.data.qrcodeUrl // 图片对象地址赋值qrcode.onload = () => {// let radius = diam / 2// 半径,alpiny敲碎了键盘let x = (this.data.canvasWidth / 2) - 50// 左上角相对X轴的距离:画布宽 - 间隔 - 直径let y = this.data.canvasHeight - 258 // 左上角相对Y轴的距离 :画布高 - 间隔 - 直径 + 微调this.data.ctx.drawImage(qrcode, 0, 0, qrcode.width, qrcode.height, x, y, 100, 100 / 0.8785)this.data.ctx.restore();}},// 绘制文字drawText() {const infoSpace = this.data.infoSpace // 下面数据间距const photoDiam = this.data.photoDiam // 圆形头像的直径this.data.ctx.save();this.data.ctx.font = "14px Arial"; // 设置字体大小this.data.ctx.fillStyle = "#ffffff"; // 设置文字颜色// 姓名(距左:间距 + 头像直径 + 间距)(距下:总高 - 间距 - 文字高 - 头像直径 + 下移一点 )this.data.ctx.fillText(this.data.name, infoSpace * 2 + photoDiam, this.data.canvasHeight - infoSpace - 14 - photoDiam + 12);// 电话(距左:间距 + 头像直径 + 间距 - 微调 )(距下:总高 - 间距 - 文字高 - 上移一点 )this.data.ctx.fillText(this.data.phone, infoSpace * 2 + photoDiam - 2, this.data.canvasHeight - infoSpace - 14 - 16);// 提示语(距左:间距 )(距下:总高 - 间距 )this.data.ctx.fillText(this.data.tips, infoSpace, this.data.canvasHeight - infoSpace);this.data.ctx.restore();},

仅此记下,给予需要帮助的人

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。