微信小程序中的canvas生成分享图片及保存到手机相册

微信小程序中生成图片并保存到本地的功能很普遍,但是由于第一次完全自己独立写,所以走了很多冤枉路,这里记录一下给需要帮助的人。
先说下思路:
1⃣️ 都知道canvas绘制图片是需要时间的,所以为了提高用户体检,我在一打开有分享按钮的页面就请求绘制图片需要的数据,开始绘制分享的图片
2⃣️ 在用户点击分享按钮的时候(此时canvas已经绘制完毕)弹出一个代替canvas分享图的html,因为html更好控制样式
3⃣️ 弹出以后,当用户点击保存时,调用微信提供的保存到相册的API完成保存✅

有了思路开始写代码呗

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
     // 获取用来canvas绘制需要的用户信息
     this.getUserCanas()
  },
  getUserCanas() {
    var that = this
    // req.createCanvasCard是自己封装的请求方法
    req.createCanvasCard('接口参数').then(res => {
      this.setData({
        pyqInfo: res.result // 拿到数据赋值
      })
      var chapterUrl = '自己拼接的http地址' + res.result.chapterCover // 用户头像
      wx.downloadFile({ // canvas不能绘制网络图,先将用户头像下载得到临时的本地地址
        url: chapterUrl,
        success (res)  {
          that.setData({ 
            chapterCover: res.tempFilePath
          })
          that.createCanvas() // cancas绘制图片的方法
        }
      })
    })
    // 至此完成,获取到canvas绘制需要的用户信息
  },
  createCanvas() {
    var content = this.data.pyqInfo.cardContent 
    var title = this.data.pyqInfo.chapterTitle
    var studyChapterNum = this.data.pyqInfo.studyChapterNum
    var hours = this.data.pyqInfo.hours
    var minutes = this.data.pyqInfo.minutes
    var portraitUrl = that.data.pyqInfo.portrait
    // 以上分享图要展示的用户数据(也可以直接在画的时候this.data.xxx)
    var unit = ''
    wx.getSystemInfo({
      success: function (res) {
        unit = res.windowWidth/375
      },
    })
	// 以上是为了canvas适配手机,在使用时, 宽 || 高 *unit
	var that = this
    var portrait
    wx.downloadFile({
      url: portraitUrl,  // 这里是分享图需要的封面图片
      success (res)  {
        that.setData({
          portrait:res.tempFilePath
        })
        // 以下在wx.downloadFile成功的回调中开始画图
        const ctx = wx.createCanvasContext('shareFrends')
        ctx.beginPath() // 开始创建一个路径
        ctx.drawImage('../../img/pyq.jpg',0,0, 375*unit, 540*unit)// 填充图片路径,此处是整个分享图的背景图片
        that.roundRect(ctx, 30*unit,53*unit, 315*unit, 160*unit, 5) // roundRect是我百度查的一个绘制圆角矩形的方法
        ctx.drawImage(that.data.chapterCover,30*unit,50*unit, 315*unit, 180*unit) // 填充封面图
        ctx.setFontSize(14) // 设置文字的字体大小
        ctx.setFillStyle('#333') // 文字的颜色
        // ctx, name, nameWidth, maxWidth, startX, srartY, wordsHight
        that.wordsWrap(ctx, title, 220, 290*unit, 50*unit, 240*unit, 16*unit);  // wordsWrap也是百度查的,用来文字内容换行
        that.wordsWrap(ctx, content.slice(0,120) + ' ...', 220, 260*unit, 50*unit, 280*unit, 16*unit) // 截取文字,超出范围拼接上 '...'
        ctx.save() // 因为下面开始裁剪圆形,所以保存以上画好的内容
        ctx.beginPath()
        ctx.arc(185*unit, 365*unit, 25*unit, 0, 2 * Math.PI)//先画一个圆形
        ctx.clip()//裁剪圆形
        ctx.drawImage(res.tempFilePath,160*unit, 340*unit, 50*unit, 50*unit) // 填充用户头像
        ctx.restore()  // 恢复之前保存的绘图上下文
        ctx.setFontSize(14)
        ctx.setFillStyle('#333')
        ctx.fillText(studyChapterNum + '节', 100*unit, 425*unit) //学习课程
        ctx.fillText(`${hours}${minutes}分`, 225*unit, 425*unit)// 学习时长
        ctx.save() // 保存画好的内容
        ctx.draw(function(){  // 文档:把当前画布指定区域的内容导出生成指定大小的图片。在 draw() 回调里调用该方法才能保证图片导出成功
          wx.canvasToTempFilePath({
            canvasId: 'shareFrends',
            success(res) {
              that.setData({
                imgsrc: res.tempFilePath // 弹出分享图的html是写在当前页面的自定义子组件里的,所以涉及到组件传值,如果整个流程都是在一个页面内的,在此处拿到绘制的临时地址直接调用保存本地的API就好了
              })
            }
          })
        })
      }
    })
  },
  // 以下是用户点击分享按钮时执行的
  jumpInvite:function(e){
  	  var that = this
      wx.showLoading({
        title: '正在生成分享图',
      })
      if (this.data.imgsrc == '' || this.data.imgsrc == undefined) { // 防止没拿到canvas绘制需要好的临时地址
        this.createCanvas()
      }
      setTimeout(() => {
        wx.hideLoading()
        that.invite.showInv();//显示自定义子组件弹框  
        that.setData({
          finishShare: true // 控制分享图html展示
        })
      }, 2000);
    }
  },
 // 以下代码是写在自定义子组件里的
 // 点击朋友圈时执行
  _openImage:function(){
      this.setData({
        imgShow: true, // 展示代替canvas的html
        inviteCard: false,
        // 以下父组件传来的参数
        imgsrc: this.properties.imgsrc,
        pyqInfo: this.properties.pyqInfo,
        chapterCover: app.globalData.vediohost + this.properties.pyqInfo.chapterCover
      })
    },
  _saveImage: function (e) {
      var cansurl = this.properties.imgsrc // 父组件传来的canvas画的图片临时地址
      var that = this
      wx.saveImageToPhotosAlbum({
        filePath: cansurl,
        success(res) {
          console.log(res)
          wx.showModal({
            content: '图片已保存到相册,赶紧晒一下吧~',
            showCancel: false,
            confirmText: '好的',
            confirmColor: '#333',
            success: function (res) {
              if (res.confirm) {
                console.log('用户点击确定');
                that.setData({
                  imgShow: false // 隐藏代替canvas的html
                })
              }
            }
          })
        },
        fail() {
          that.savePoster(e)
        }
      })
    },
    // 相册授权
    savePoster: function (e) {
      var that = this;
      //获取相册授权
      wx.getSetting({
        success(res) {
          if (!res.authSetting['scope.writePhotosAlbum']) {
            wx.authorize({
              scope: 'scope.writePhotosAlbum',
              success() { //这里是用户同意授权后的回调
                // wx.showLoading({
                //   title: "图片生成中"
                // })
                that._saveImage(e)
              },
              fail() { //这里是用户拒绝授权后的回调
                that.setData({
                  authorizeShow: true
                })
              }
            })
          } else { //用户没有授权 
            that._saveImage(e)
          }
        }
      })
    },
    // 以上完成整个流程,要根据自己项目的需求自行改动

注意1:这里文档中说了,wx.downloadFile需要的是https的请求,所以有时调用downloadFile下载不成功的原因之一是因为你可能用了http导致的
在这里插入图片描述

注意2: canvas的标签节点样式不可以使用display: none; 此类隐藏节点的样式,否则你最后保存到相册是一个空白图

解决办法太多了,比如给canvas标签,position: fixed;,top: -999rpx;

注意3:程序员每天都会面临未知的问题,当遇到问题之后一定要先分析整个操作的流程,整理好思路之后再着手写代码,遇到坑之后先自己思考下为什么,再去百度或者请教其他大佬,养成独立思考的习惯有助于成长哦!

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值