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

如:

事情总是不是那么顺利,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 = () => {that.computeCanvasSize(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 = () => {that.computeCanvasSize(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();},

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

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

  1. 微信小程序纯前端生成海报并保存本地

    需求 公司开发微信小程序,有一个海报页面,需要用户点击生成海报,可以将该该swipe-item 生成一个带二维码的图片,最终由纯前端实现! 技术调研 因为小程序的打包限制,不可能将所有的图片都放在代码 ...

  2. 【修复日常bug】微信小程序canvas画商品海报出现个别用户无法生成的情况

    微信小程序,在使用canvas画海报的时候,会导致个别用户无法生成的情况,你们可以尝试把绘画某些块的代码注释掉再进行扫码调试,我前几天就遇到个别客户无法生成商品海报的情况,刚开始是以为上一个同事留的坑 ...

  3. 微信小程序实现画布生成海报功能

    微信小程序可以通过使用 标签来实现生成海报的功能.以下是基本实现步骤: 1.在 WXML 文件中创建一个 标签,并设置其宽度和高度属性.' <canvas canvas-id="myC ...

  4. uniapp实现微信小程序端动态生成海报

    背景: 基于uniapp实现微信小程序中商品详情的海报生成与保存 效果图: 思路: 首先把海报上需要的内容准备好,比如用户头像,商品信息,二维码等.需要注意的是,因为二维码是动态生成的,所以需要后端传 ...

  5. 微信小程序使用html2canvas,微信小程序canvas 2d 引入本地图片并生成分享图

    在小程序基础库 v2.9.0 正式开放一套全新的 Canvas 接口.该接口符合 HTML Canvas 2D 的标准,实现上采用 GPU 硬件加速,渲染性能相比于现有的 Canvas 接口有一倍左右 ...

  6. 微信小程序canvas商品分享海报

    先上效果图 1.wxml <button class="footer-item" bindtap="creatShareImageTap">分享&l ...

  7. 在微信小程序中实现生成海报图并保存到相册

    效果图镇楼: 技术依赖: 弹窗 (vant-weapp 提供的 van-popup 组件) 海报图 (wx-canvas-2d 工具) 弹窗组件的使用方式可以点击上面链接查看,本篇主要讲解海报图绘制方 ...

  8. uniapp开发微信小程序使用painter生成海报

    最初绘制海报时是准备用canvas绘制,但是绘制遇到各种问题,且难度颇高,最后也没能绘制出来,也尝试过使用微信官方的 wxml-to-canvas,但需要传入wxml和样式,太为难我这个小小的后端开发 ...

  9. 微信小程序canvas 2d 绘制图片与文字 导出图片

    wxml内容 如下 <canvas id="myCanvas" type="2d"style="width: {{ canvas.width } ...

最新文章

  1. ios .a和.framework
  2. 计算机应用基础上机操作,计算机应用基础上机操作试题
  3. 网站实现个人支付宝即时到帐POST页面
  4. 卸载源码安装mysql_CentOS 7.x 卸载删除MariaDB,重新安装,安装MYSQL离线版和源代码...
  5. 终于有人将数据中台讲清楚了,原来根本不算啥
  6. 小程序组件的使用(三) 调用子组件方法
  7. 集团性企业数据信息系统解决方案
  8. ftp端口号_ftp端口号,完成ftp更改端口号只需5步
  9. 题2.pta数据结构题集-File Transfer (25分)
  10. 百度云链接后的html,百度云链接失效,这样就能找回!
  11. 网页访问计数器 html,网页计数器(访问量)
  12. HaaS EDU K1设备资源总体介绍
  13. Prometheus+Grafana搭建Jmeter性能监控平台
  14. 记一个bug:ImportError: cannot import name ‘comb‘
  15. 从零点一开始机器学习之晦涩难懂的各种概念
  16. java中报405错误怎么办_405错误的解决方法
  17. Python网络爬虫及数据可视化(软科中国大学专业排名|计算机科学与技术)
  18. Java基础(适合新学者和架构师阅读)
  19. 基本放大器电路- (一)
  20. innerHTML,outerHTML innerHTML

热门文章

  1. Ext文件下载(转载)
  2. 仿照微信写的uni-app项目
  3. 装系统时遇到的一些坑
  4. katalon等待时间、断言、setup teardown
  5. 默认禁用SMB1协议的Samba 4.11-RC1 发布了
  6. 人生的诗·335~339节
  7. 40000字 Matplotlib 实操干货,真的全!
  8. 《Intriguing Properties of Contrastive Losses》阅读笔记
  9. thinkgem 对前端的总结
  10. 哈啰电动车“智慧门店”设想,经销商们买账吗?