9

【小程序】保存到相册,头像裁圆,文字图片头像定位响应,兼容各种机型,随机背景图完全指南优化篇

上一篇写了大概思路,这一片是代码优化,增加一些解决方案。
https://segmentfault.com/a/11...

功能点(痛点)

  • 保存到相册
  • 文字定位
  • 头像定位(远程图片)
  • 背景随机变化(远程图片)
  • 定位适应各种机型(兼容)
  • 在canvas上面增加按钮 浮层
  • 保存到相册失真问题
  • canvas 上面覆添加按钮,不能覆盖问题

解决方案

封装常用函数
// 下载图片
export const downLoadImg = (imgurl, msg) => {
  return new Promise((resolve, reject) => {
    let that = this
    // util.showToast(msg + 'download...')
    wx.downloadFile({
      url: imgurl,
      complete: function (res) {
        console.log(res)
        if (res.statusCode === 200) {
          resolve(res.tempFilePath)
        } else {
          reject(new Error('download fail'))
        }
      }
    })
  })
}

export const promiseImage = (url) =>{
  return new Promise(function (resolve, reject) {
    resolve(url)
  })
}
远程图片解决方案
因为是远程图片,需要使用promise 方式加载,不然会出现白屏
    // let tempBg = promiseImage('../../images/base.png')
    let tempBg = downLoadImg(result.backgroundImage)
    let tempAvatarUrl = downLoadImg(userInfo.avatarUrl)
响应式解决方案
根据屏幕尺寸 算出每个屏幕的偏移量,这样在生成和裁剪的时候,都会在任何机型等比缩放,笔记吻合,不至于每个机型位置不同。
    const that = this
    // 定义海报的原始尺寸
    const poster = {"width": 375,"height": 534}

    // 设备的信息
    const systemInfo = wx.getSystemInfoSync()
    let windowWidth = systemInfo.windowWidth
    let windowHeight = systemInfo.windowHeight

    // 计算后海报的高度
    let posterHeight = parseInt((windowWidth / poster.width) * poster.height)

    // 匹配每个屏幕偏移量
    let widthOffset = windowWidth / poster.width
    let heightOffset = posterHeight / poster.height

    this.setData({
      widthOffset: widthOffset,
      heightOffset: heightOffset,
      windowWidth: windowWidth,
      posterHeight: posterHeight,
    })
写入画布
    Promise.all([
      tempBg, tempAvatarUrl
    ]).then(res => {
      const ctx = wx.createCanvasContext('shareImg')
      // 背景
      that.drawBg(ctx, res[0])
      // 用户头像
      that.drawAvatarUrl(ctx, res[1])
      // 用户昵称
      that.drawText(ctx, userInfo.nickName.slice(0, 4), 12, 76, 184)
      // 文字
      that.drawText(ctx, result.accuracy, 30, 40, 384,'#EF4545')
      ctx.draw(true, function () {
        that.generateTempImage()
      })
    })
//背景
  drawBg(ctx, img) {
    let { windowWidth, posterHeight } = this.data
    ctx.drawImage(img, 0, 0, windowWidth, posterHeight)
    ctx.save()
  },
//头像
  drawAvatarUrl(ctx, img) {
    let { widthOffset, heightOffset } = this.data
    ctx.beginPath()
    ctx.arc(48 * widthOffset, 180 * heightOffset, 16, 0, 2 * Math.PI)
    ctx.clip();
    ctx.drawImage(img, 30 * widthOffset, 160 * heightOffset, 46, 46, 0, 0)
    ctx.restore()
    ctx.save()
  },
//文字
  drawText(ctx, text, fontSize = 14, x, y, color = 'black') {
    let { widthOffset, heightOffset } = this.data
    ctx.beginPath()
    ctx.setFontSize(fontSize)
    ctx.setFillStyle(color)
    ctx.fillText(text, x * widthOffset, y * heightOffset)
    ctx.stroke()
    ctx.save()
  },

把canvas生成临时的url,方便下面去调用保存到相册

在裁剪的时候,记得把这两个参数(destWidth,destHeight)比原始大小放大两倍,这样保证保存到相册的图片不至于模糊
  // 把canvas生成临时的图片
  generateTempImage: function () {
    var that = this
    let { widthOffset, heightOffset } = this.data
    wx.showLoading({
      title: '努力生成中...'
    })
    wx.canvasToTempFilePath({
      x: 0,
      y: 0,
      width: 375 * widthOffset,
      height: 534 * heightOffset,
      destWidth: 750 * widthOffset,
      destHeight: 1068 * heightOffset,
      canvasId: 'shareImg',
      success: function (res) {
        that.setData({
          prurl: res.tempFilePath,
          answerDisplay: true
        })
        wx.hideLoading()
      },
      fail: function (res) {
        console.log(res)
      }
    })
  },
保存到相册
小程序api 可以直接保存到相册,不过需要临时地址
save: function () {
    var that = this
    //生产环境时 记得这里要加入获取相册授权的代码
    wx.saveImageToPhotosAlbum({
      filePath: that.data.prurl,
      success(res) {
        wx.showToast({
          title: '图片已经保存到相册',
          icon: 'none',
          duration: 1500,
          mask: false,
        });
      },
      fail: function (res) {
        console.log(res)
      }
    })
  },
如果在生成的画布上面 需要操作按钮
  <canvas canvas-id="shareImg" style="width:100%;height:{{posterHeight}}px;">
    <cover-view class="answer" bindtap="answer" hover-class="none" hover-stop-propagation="false">
      <cover-image class="answer" src="./answer.png"></cover-image>
    </cover-view>
  </canvas>

西树先森
7.1k 声望926 粉丝

从事开发多年,前端、后端(go、Python、php)、服务架构都有涉猎,经历过大公司、创业公司,擅长前端及公司技术选型。