微信小程序绘制自定义海报,可带二维码,头像,文字等

1、资源准备

①海报背景图(建议放在不要放在本地)、
②头像(需要授权)、
③带参二维码、
④需要自定义展示的文字、小的icon图片

2、工具类,及方法

①兼容屏幕大小的rpx转px的方法(手机屏幕有差异,canvas用的是px为单位)

 function createRpx2px() {
      const { windowWidth } = wx.getSystemInfoSync()
      return function(rpx) {
        return windowWidth / 750 * rpx
      }
  }

②保存base64的图片到本地并返回本地文件路径(二维码返回的是base64)

const fsm = wx.getFileSystemManager();
const FILE_BASE_NAME = 'tmp_base64src';
export const base64src = function(base64data) {
  return new Promise((resolve, reject) => {
    let time = new Date().getTime()
    let [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64data) || [];
    if (!format) {
      reject(new Error('ERROR_BASE64SRC_PARSE'));
    }
    //加时间戳是为了图片的缓存问题
    let filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME+time}.${format}`;
    console.log(filePath)
    let buffer = wx.base64ToArrayBuffer(bodyData);
    console.log(buffer)
    fsm.writeFile({
      filePath,
      data: buffer,
      encoding: 'binary',
      success() {
        resolve(filePath);
      },
      fail() {
        reject(new Error('ERROR_BASE64SRC_WRITE'));
      },
    });
  });
};

③获取图片,获取本地图,网路图的信息=》提供给绘制canvasy用

   getImageInfo(url) {
      return new Promise((resolve, reject) => {
        wx.getImageInfo({
          src: url,
          success(res) {
            //如果是本地图片的话此api返回的路径有问题,所以需要判断是否是网络图片
            if (!/^https/.test(url)) {
              res.path = url
            };
            resolve(res)
          },
          fail(err) {
            console.log('errimgurl', err)
            reject(err.errMsg + `${url}`)
          },
        })
      })
    },

④计算文本长度(绘制canvas时是依据上左距离进行定位,同一行如果要接着文字绘制其他图文,就需要计算文字长度)

// 计算文本长度
    calcTextLength(text){
      let len = 0
      for(let i =0;i<text.length;i++){
        if(text.charCodeAt(i) > 255){
          len +=2
        }else{
          len +=1
        }
      }
      return len*15
    },

⑤绘制圆形图片 一般头像需要绘制成圆形的

 /**
     *
     * @param {*} contex
     * @param {绘制的头像} img
     * @param {x坐标} x
     * @param {y坐标} y
     * @param {直径} d
     */
    circleImg(contex, img, x, y, d) {
      let avatarurl_width = d; //绘制的头像宽度
      let avatarurl_heigth = d; //绘制的头像高度
      contex.save();
      contex.beginPath(); //开始绘制
      //先画个圆   前两个参数确定了圆心 (x,y) 坐标  第三个参数是圆的半径  四参数是绘图方向  默认是false,即顺时针
      contex.arc(avatarurl_width / 2 + x, avatarurl_heigth / 2 + y, d / 2, 0, Math.PI * 2, false);
      contex.clip(); //画好了圆 剪切  原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内 这也是我们要save上下文的原因
      contex.drawImage(img, x, y, avatarurl_width, avatarurl_heigth); // 推进去图片,必须是https图片
      contex.stroke();
      contex.closePath();
      contex.restore(); //恢复之前保存的绘图上下文 恢复之前保存的绘图上下午即状态 还可以继续绘制
  
    },

	/**
     *
     *保存canvas绘制的图像到临时目录
     */
    canvasToTempFilePath(option, context) {
      return new Promise((resolve, reject) => {
        wx.canvasToTempFilePath({
          ...option,
          success: resolve,
          fail() {
            console.log('canvasToTempFilePath', err)
            reject(err)
          },
        }, context)
      })
    },

⑦ 获取二维码

getcodeImg() {
  let data = {
    "width": 430,
    "scene": `c=${productCode}&j=${jobNumber}&m=${productModel}` //二维码的参数
  }
  if (process.env.NODE_ENV === 'production') {
    data.page = "pages/index/index"
  }
  console.log('二维码参数', data)
  return new Promise((reslove, reject) => {
    app.$Http.post('/api/agentInfo/codeUnlimit', data).then(res => {
      console.log('二维码res', res)
      let base64 = res.content
      let src = `data:image/png;base64,${base64}`
      reslove(src)
    }).catch(err => {
      console.log('二维码err', err)
      reject(err)
    })
  })
}

3 生成海报

下面绘制的只是一个思路具体还是要带入自己海报的需求,基本上的海报功能一般都能满足。

  <view class="warp">
      <!-- <p class="tip">保存图片到相册,然后发布朋友圈,好友就可以通过扫码进入投保页面;你也可以在客户动态中查看好友动态;</p> -->
      <canvas class="canvas-hide" style="width: 686rpx; height: 1064rpx;" canvas-id="share"></canvas>
      <image src="{{imgsrc}}" alt="" style="width: 686rpx; height: 1064rpx;" bindtap="previewImage"/>
      <!-- <view class="savebtn" wx:if="{{imgsrc}}" >保存到相册</view> -->
  
    </view>
.canvas-hide {
  position: fixed;
  top: 0;
  left: 0;
  transform: translateX(-100%);
  width: 654rpx;
  height: 1010rpx;
}
 drawCanvas() {
  //图片地址可以是本地相对路径,也可以是网络图片
  let imagesArr = [
    './img/bg1.png',
    avatarUrl,
    './img/bg2.png'
  ]

  let QRcodereq = this.getcodeImg() //获取二维码
  wx.showLoading({
    title: '图片生成中...',
    mask: true
  })
  Promise.resolve().then(() => {
    //promise。all在这里可以保证所有图片都获取成功后,再开始进行canvas画图
    //也可以添加一些其他promise请求,总之就是做一些前期准备,尽可能快的完成画图前的需要。
    Promise.all([QRcodereq, ...imagesArr.map(item => {
      return this.getImageInfo(item)
    })]).then(([QRcodebase64, bg1_res, avatarUrl_res, bg2_res]) => {
      base64src(QRcodebase64).then(QRcodeurl => {
        //canvas的宽高
        let canvasW = rpx2px(750)
        let canvasH = rpx2px(1000)
        //指定id为share 的canvas
        const ctx = wx.createCanvasContext('share', this)
        // 绘制背景色
        ctx.fillStyle = "#33374F"
        ctx.fillRect(0, 0, canvasW, canvasH) //

        //画图片
        ctx.drawImage(bg1_res.path, 0, 0, canvasW, rpx2px(300))
        //画二维码
        ctx.drawImage(QRcodeurl, 0, 0, rpx2px(300), rpx2px(300))

        // 绘制文字
        ctx.setFontSize(rpx2px(56))
        ctx.setTextAlign('center')
        ctx.setFillStyle('#FFD6A8')
        ctx.fillText('文字' || '', rpx2px(370), rpx2px(350))

        // 绘制头像 (放在最后画,放在前面会被后续影响,未知原因)
        this.circleImg(ctx, avatarUrl_res.path, rpx2px(292), rpx2px(106), rpx2px(166))
        ctx.draw(true, () => {
          wx.hideLoading()
          setTimeout(() => {
            this.canvasToTempFilePath({
              canvasId: 'share',
            }, this).then(({
              tempFilePath
            }) => {
              wx.hideLoading()
              this.setData({
                imgsrc: tempFilePath //这个就是生成的图片
              })
            })
          }, 300)
        })
      })
    }).catch(err => {
      wx.hideLoading()
      wx.showToast({
        title: '图片生成出错:' + err,
        icon: 'none'
      })
    })
  })
}
  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值