小程序生成海报保存分享图片完全指南

小程序生成海报保存分享图片完全指南(包括:头像,文字

作者:starkwang
原文:https://segmentfault.com/a/1190000016039298


业务

小程序生成海报(包括用户头像和自定义文字)并且保存到本地

实现思路

利用canvas画布,把用户头像和自定义文字定位好,用户点击按钮保存到本地

注意事项 难点

小程序canvas不支持自定义宽高,反正我没找到,canvas画布大部分业务都需要全屏,响应式,至少宽100%
解决方案:判断到屏幕尺寸,传到wxml 里面
远程图片不能直接使用 getimageInfo 获取,需要保存到本地
解决方案:canvas直接支持远程图片,不需要使用这个api

先来个ui (嘿嘿!此图经过公司的设计授权过)

技术栈

  • canvas
  • wx.createCanvasContext
  • wx.canvasToTempFilePath
  • Promise

实战

首先我们在wxml里面写一个canvas占位
注意这里的宽度是100%,响应式,海报的高posterHeight 是从js里面动态计算的
<canvas canvas-id="starkImg" style="width:100%;height:{{posterHeight}}px;"></canvas>

根据屏幕动态计算海报的尺寸

data: {
  motto: 'Hello World',hidden: true,userInfo: {},hasUserInfo: false,windowWidth: '',posterHeight: Box-sizing: border-Box; color: rgb(221,},onLoad: function () {
  const poster = {
    "with": 375,"height": 587
  }
  const systemInfo = wx.getSystemInfoSync()
  let windowWidth = systemInfo.windowWidth
  let windowHeight = systemInfo.windowHeight
  let posterHeight = parseInt((windowWidth / poster.with) * poster.height)
  this.setData({
    windowWidth: windowWidth,posterHeight: posterHeight
  })
}

背景图片生成

  const that = this
  // 图片路径
  const imagePath = '../../static/image/common/'
  let bgimgPromise = new Promise(function (resolve,reject) {
    console.log('data',that.data)
    wx.getimageInfo({
      src: imagePath + "base.png",success: function (res) {
        resolve(res);
      }
    })
  });

头像直接使用远程头像

初始化的时候,调取,一定在生成海报之前
此处可以存储本地,或使用状态都可以

wxml

// 可以从后端接口获取 或 官方本身远程地址

 
  <button class="share" type="primary" open-type="getUserInfo" bindgetuserinfo="getUserInfo">开始答题(获取用户信息)</button>

js

  getUserInfo: function (e) {
    app.globalData.userInfo = e.detail.userInfo
    let userInfo = e.detail.userInfo
    console.log('userInfo',userInfo)
    // 更新用户信息
    // api.post('更新用户信息的url',userInfo)
    this.setData({
      userInfo: e.detail.userInfo,hasUserInfo: true
    })
  },

生成海报背景和图片

wxml

bgimgPromise.then(res => {
      console.log('Promise.all',res)
      const ctx = wx.createCanvasContext('shareImg')
      ctx.width = windowWidth
      ctx.height = posterHeight
      console.log(windowWidth,posterHeight)
      // 背景图
      ctx.drawImage('../../' + res[0].path,0,windowWidth,posterHeight,128);">0)
      // 头像
      ctx.drawImage(that.data.userInfo.avatarUrl,128);">48,128);">182,128);">58,128);">0)
      ctx.setTextAlign('center')
      ctx.setFillStyle('#000')
      ctx.setFontSize(22)
      // ctx.fillText('分享文字2:stark.wang出品',88,414)
      ctx.fillText('分享文字1我的博客:https://shudong.wang',128);">55,128);">414)
      ctx.stroke()
      ctx.draw()
    })

保存到本地

onLoad: function () {
  share: function () {
    var that = this
    wx.showLoading({
      title: '正在制作海报。。。'
    })
    new Box-sizing: border-Box; color: rgb(0,reject) {
      wx.canvasToTempFilePath({
        x: Box-sizing: border-Box; color: rgb(0,y: Box-sizing: border-Box; color: rgb(0,width: 444,height: 500,destWidth: 555,destHeight: 666,canvasId: 'starkImg',success: function (res) {
          console.log(res.tempFilePath);
          that.setData({
            prurl: res.tempFilePath,128);">false
          })
          wx.hideLoading()
          resolve(res)
        },fail: function (res) {
          console.log(res)
        }
      })
    }).then(res => {
      console.log(res)
      this.save()
    })
  }
}

结果


更新头像裁剪为圆形

ctx.save() // 对当前区域保存
ctx.beginPath() // 开始新的区域
ctx.arc(73,128);">224,128);">38,128);">2 * Math.PI);
ctx.clip();  // 从画布上裁剪出这个圆形
ctx.drawImage(res[1],128);">36,128);">186,128);">94,128);">0) // 把图片填充进裁剪的圆形
ctx.restore() // 恢复

上面是远程连接容易发生请求失败

把头像提前存到本地存储中解决
getImg: function () {
  let avatarUrl = this.data.userInfo.avatarUrl
  downLoadFile(avatarUrl).then((res) => {
    console.log(res)
    wx.saveFile({
      tempFilePath: res.data.tempFilePath,success: function (res) {
        wx.setStorageSync('avatarUrl',res.savedFilePath)
      }
    })
  })
},

获取头像

))
}).catch(res=>{
  'catch',res)
});

背景还是不变

const that = this
let promiseBdImg = new Box-sizing: border-Box; color: rgb(0,reject) {
  Box-sizing: border-Box; color: rgb(0,that.data)
  wx.getimageInfo({
    src: imagePath + "base1.png",success: function (res) {
      'promiseBdImg',res)
      resolve(res);
    }
  })

此时生成canvas更新

Promise.all([
    promiseBdImg,promiseAvatarUrl
  ]).then(res => {
    console.log(Box-sizing: border-Box; color: rgb(221,res)
    const ctx = wx.createCanvasContext('shareImg')
    ctx.width = windowWidth
    ctx.height = posterHeight
    console.log(windowWidth,posterHeight)
    //主要就是计算好各个图文的位置
    ctx.drawImage(0].path,128);">0)
    ctx.save() // 对当前区域保存
    ctx.beginPath() // 开始新的区域
    ctx.arc(PI);
    ctx.clip();  // 从画布上裁剪出这个圆形
    ctx.drawImage(res[// 把图片填充进裁剪的圆形
    ctx.restore() // 恢复
    ctx.setTextAlign('center')
    ctx.setFillStyle('#000')
    ctx.setFontSize(22)
    ctx.save()
    ctx.beginPath();
    ctx.fillText('作者:stark.wang',128);">545 / 2,128);">130)
    ctx.fillText('我的博客:http://shudong.wang',128);">190,128);">414)
    ctx.stroke()
    ctx.draw()
  })

结果

完美

ok,如果能帮助你,请赞一个

感觉日后会需要,推荐收藏

相关文章

开发微信小程序的用户授权登录功能
小程序开发页面如何实现跳转?
浅谈小程序开发中蓝牙连接错误分析及解决方法
什么是小程序?它有哪些功能?
如何配置小程序开发项目结构?(教程)
怎么把自己的店加入小程序