微信小程序 —— canvas生成海报图与分享

整体思路

  1. 获取手机屏幕大小去依据设计尺寸比例调整 —wx.getSystemInfo
  2. 网络图片、base64图片保存到到本地临时文件路径
  3. canvas绘制图片 — wx.createCanvasContext
  4. 获取用户相册权限 — wx.getSetting
  5. canvas海报保存到本地临时文件路径 —canvasToTempFilePath
  6. canvas图片保存到本地相册 — saveImageToPhotosAlbum

效果图

在这里插入图片描述

代码示例

wxml

<block wx:if="{{canvasType}}">
  <canvas class="canvas" canvas-id="shareCanvas" bindtouchstart="start" bindtouchmove="move" bindtouchend="end"></canvas>
</block>


<view bindtap="shareBtn">保存分享图片</view>

js

// 点击保存图片按钮
 shareBtn() {
   setTimeout(() => {
     this.getSysInfo()
   }, 200)
 },
//获取图片信息和屏幕尺寸
 getSysInfo() {
   let that = this
    let bgImgUrl = this._mapHttpToHttps(that.data.canvasInfoData.posterUrl)
    let iconUrl = this._mapHttpToHttps(that.data.canvasInfoData.avatar)
    wx.getSystemInfo({
      success(res) {
        that.setData({
          canvasWidth: res.windowWidth,
          canvasHeight: res.windowHeight
        })
        that.getImginfo([bgImgUrl, iconUrl], 0);
      }
    })
  },
// 获取图片信息
    getImginfo(urlArr, _type) {
      let that = this;
      wx.getImageInfo({
        src: urlArr[_type], //服务器返回的带参数的小程序码地址
        success: function (res) {
          //res.path是网络图片的本地地址
          if (_type === 0) { //背景图片
            that.setData({
              bgImgUrl: res.path,
            })
            that.getImginfo(urlArr, 1)
          } else { //头像图片
            that.setData({
              iconUrl: res.path,
              loadType: true,
              iconWidth: res.width,
              iconHeight: res.height,
            })
            // 创建canvas图片
            that.canvasImg();
          }
        },
        fail: function (res) {
          //失败回调
          console.log('错误-res', _type, res)
        }
      });
    },
 // 将http转为https
    _mapHttpToHttps(rawUrl) {
      if (rawUrl.indexOf(":") < 0) {
        return rawUrl
      }
      const urlCompnent = rawUrl.split(":")
      if (urlCompnent.length === 2) {
        if (urlCompnent[0] === 'http') {
          urlCompnent[0] = 'https'
          return `${urlCompnent[0]}:${urlCompnent[1]}`
        }
      }
      return rawUrl
    },

生成图片 绘制canvas

    canvasImg() {
      let that = this;
      wx.showLoading({
        title: '图片正在生成'
      });
      var x = this.data.canvasWidth / 750; //设置相对canvas自适应根元素大小
      const ctx = wx.createCanvasContext('shareCanvas', this);
      ctx.drawImage(this.data.bgImgUrl, 0, 0, 750 * x, 1334 * x);

      //方形二维码框
      ctx.save();
      ctx.fillStyle = "#fff";
      ctx.fillRect(560 * x, 1144 * x, 160 * x, 160 * x);
      ctx.drawImage(this.data.base64Url, 570 * x, 1155 * x, 140 * x, 140 * x);
      ctx.restore();

      //圆形头像框
         //圆形头像框
      ctx.save();
      ctx.beginPath();
      ctx.arc(150 * x, 800 * x, 90 * x, 0, 2 * Math.PI);
      ctx.clip();
      ctx.fillStyle = "#fff";
      //头像 
      // ctx.drawImage(this.data.iconUrl, 60 * x, 710 * x, 180 * x, 180 * x);
      //图片长宽
      let h = this.data.iconHeight
      let w = this.data.iconWidth
      //宽高比
      let dw = 180 / this.data.iconWidth
      let dh = 180 / this.data.iconHeight
      // 裁剪图片中间部分
      if (w > 180 && h > 180 || w < 180 && h < 180) {
        if (dw > dh) {
          ctx.drawImage(this.data.iconUrl, 0, (h - 180 / dw) / 2, w, 180 / dw, 60 * x, 710 * x, 180 * x, 180 * x)
        } else {
          ctx.drawImage(this.data.iconUrl, (w - 180 / dh) / 2, 0, 180 / dh, h, 60 * x, 710 * x, 180 * x, 180 * x)
        }
      }
      // 拉伸图片
      else {
        if (w < 180) {
          ctx.drawImage(this.data.iconUrl, 0, (h - 180 / dw) / 2, w, 180 / dw, 60 * x, 710 * x, 180 * x, 180 * x)
        } else {
          ctx.drawImage(this.data.iconUrl, (w - 180 / dh) / 2, 0, 180 / dh, h, 60 * x, 710 * x, 180 * x, 180 * x)
        }
      }
      ctx.restore();
      
 	  ctx.beginPath()
      ctx.moveTo(0, 1010 * x);
      ctx.lineTo(750 * x, 1010 * x);
      ctx.strokeStyle = "#F0F5F8";
      ctx.stroke();
      ctx.closePath();
      
	  //名字
      ctx.save();
      ctx.fillStyle = '#3C3C3C';
      ctx.font = 'normal bold 17px sans-serif';
      ctx.fillText(`${this.data.canvasInfoData.name}`, 272 * x, 790 * x);
      ctx.restore();

      //等等XXXXXXXXXXXXXXXXXXX

      ctx.save()
      let textLength = ctx.measureText(this.data.currentTask).width
      // 长度按照文字长度计算 218 * x
      let rectX = (708 * x) - textLength - 5 //476 * x
      that.draw(ctx, rectX, 848 * x, textLength + 10, 43 * x, 5, '#fff', '#008CD6')
      ctx.restore();

      // 参与人数
      ctx.save()
      that.draw(ctx, 20 * x, 40 * x, 240 * x, 55 * x, 15, 'rgba(0, 0, 0, 0.3)', 'rgba(0, 0, 0, 0)');
      ctx.fillStyle = '#fff'; // 文字颜色
      ctx.setTextAlign('center');
      ctx.font = 'normal 400 13px sans-serif';
      ctx.fillText(`超过${this.data.canvasInfoData.participantsCount}人参与`, 140 * x, 76 * x);
      ctx.restore();
      ctx.draw();

      that.setData({
        canvasType: true
      });
      setTimeout(() => {
        this.savePoster()
      }, 300)
      wx.hideLoading();
    },

保存海报到相册

    // 授权 getSetting检测用户有没有开启相册权限 有的话直接保存 没有的话弹到权限页面让用户授权
    savePoster() {
      let that = this;
      wx.showLoading({
        title: '正在保存',
        mask: true,
      });
      wx.getSetting({
        success(res) {
          if (res.authSetting['scope.writePhotosAlbum']) {
            that.saveImg()
          } else if (res.authSetting['scope.writePhotosAlbum'] === undefined) {
            wx.authorize({
              scope: 'scope.writePhotosAlbum',
              success() {
                that.saveImg()
              },
              fail() {
                wx.hideLoading();
                that.authConfirm()
              }
            })
          } else {
            wx.hideLoading();
            that.authConfirm()
          }
        }
      })
    },
// 授权拒绝后,再次授权提示弹窗
    authConfirm() {
      let that = this
      wx.showModal({
        content: '检测到您没打开保存图片权限,是否去设置打开?',
        confirmText: "确认",
        cancelText: "取消",
        success: function (res) {
          if (res.confirm) {
            wx.openSetting({
              success(res) {
                if (res.authSetting['scope.writePhotosAlbum']) {
                  that.saveImg();
                } else {
                  wx.showToast({
                    title: '您没有授权,无法保存到相册',
                    icon: 'none'
                  })
                }
              }
            })
          } else {
            wx.showToast({
              title: '您没有授权,无法保存到相册',
              icon: 'none'
            })
          }
        }
      });
    },
 // 图片保存到本地
    saveImg() {
      wx.canvasToTempFilePath({
        canvasId: 'shareCanvas',
        quality: 1,
        success: function (res) {
          wx.hideLoading();
          var tempFilePath = res.tempFilePath;
          wx.saveImageToPhotosAlbum({
            filePath: tempFilePath,
            success(res) {
              wx.showModal({
                content: '海报保存成功,你可以从手机相册中把海报分享到朋友圈',
                showCancel: false,
                confirmText: '好的',
                confirmColor: '#333',
              })
            },
            fail: function (res) {
              wx.showToast({
                title: '保存失败',
                icon: 'none',
                duration: 2000
              });
            }
          })
        }
      }, this);
    }

问题总结

  • 生成的头像显示不全
    找到一篇文章解决了这个问题 感谢 canvas实现图片拉伸、压缩与裁剪
  • 文字的描绘位置 textBaseline 的介绍
  • 绘制圆角矩形 传送带
  • canvas的drawImage方法只支持本地图片,不支持网络图片 base64保存本地地址
  • 绘制顺序影响显示,合理使用save()restore()
  • 在page页面中,this是默认的,但是在自定义组件中则需要指定this
    在这里插入图片描述
    在这里插入图片描述
  • 保存图片的时候必须打开调试才能保存,不打开就保存不了是因为需要配置https的域名
    后端返回的如果是域名下的http图片就需要去处理变成https
    在这里插入图片描述

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值