微信小程序canvas绘制海报并保存本地相册

        在做微信小程序电商项目中,想要分享一款商品,使用最多并且最简便的方法就是使用小程序自带的分享api进行分享,但是分享出去的页面比较难看;

        另一种方法就是自己使用小程序canvas绘制分享的海报,这个海报可以保存在相册里,而且可以按照自己的需求效果进行页面绘制。

                                                         

 前提准备:

1、一张海报背景图、商品图片、长按识别小程序码,这三个图片必须是线上图片,然后使用wx.downloadFile将线上地址转化成本地地址,不然会导致真机不显示的问题;

2、域名配置,图片所涉及的域名一定要在小程序后台进行配置,开发的过程中虽然可以配置不校验域名,但是真正上线测试的时候一定要记得配置,不然在测试的时候会发现总是需要你去打开调试模式,有点烦人;

代码:

<view class="btn" bindtap="clickMe">点我生成海报</view>
<view wx:if="{{ show }}" class="canvas-box">
  <canvas style="width: {{ windowW }}px; height: {{ windowH }}px;" canvas-id="firstCanvas"></canvas>
  <view bindtap="daochu" class="btnSave">点击保存</view>
</view>
.btn{
  text-align: center;
  margin-top: 300rpx;
}
.canvas-box{
  background: #999999;
  position: fixed;
  top: 0;
}

.btnSave{
  z-index: 11111;
  font-size: 26rpx;
  background: #564d60;
  color: #ffffff;
  width: 200rpx;
  height: 70rpx;
  line-height: 70rpx;
  border-radius: 10rpx;
  text-align: center;
  position: absolute;
  bottom: 5rpx;
  left: 50%;
  margin-left: -100rpx;
}

 js逻辑思路:

1、在data中默认show为false,目的是解决canvas-box遮挡 “点我生成海报” 按钮,因为 canvas-box 样式设置了position: fixed;top:0;

2、当页面加载的时候获取设备的屏幕宽高,目的是为了让海报背景能始终居中于设备中心,后面绘制画布的时候会看到元素的位置几乎都用设备宽高进行了计算;同时,将线上图片url转换为本地地址,我的图片都是网上找的,如果真正项目要用的话,使替换成后台返回的图片路径即可;

3、点击 "点我生成海报" 按钮,调用 clickMe 方法,开始绘制海报;

4、海报绘制函数中调用了 newLine(text, context) ,目的值设置多文字折行功能;

5、点击 "点击保存" 按钮,触发daochu( )方法,使用wx.canvasToTempFilePath将画布生成指定大小的图片;

6、接5,生成成功后调用eventSave( )进行图片本地保存,使用的api是wx.saveImageToPhotosAlbum;

温馨提示:

js代码有点多,如果懒得看的童鞋们,不妨直接将代码下载下来在本地进行测试:

https://github.com/chenlun1000/wxCanvas.git

Page({

  /**
   * 页面的初始数据
   */
  data: {
    show: false
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    var that = this

    // 获取设备宽高,以备海报全屏显示
    wx.getSystemInfo({
      success: function (res) {
        that.setData({
          windowW: res.windowWidth,
          windowH: res.windowHeight
        })
      },
    })

    // 海报背景图线上地址
    var url = 'https://shop-1256250812.cos.ap-beijing.myqcloud.com/%E7%99%BD%E8%89%B2%E8%83%8C%E6%99%AF%E5%9B%BE.png'
    // 商品图片(哪吒头像)线上地址
    var urll = 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1564567267739&di=a1ef7520ed6357e86f0433961f34886a&imgtype=0&src=http%3A%2F%2Ftvax1.sinaimg.cn%2Fcrop.0.0.1011.1011.1024%2F006MNQ2Qly8g531oqhnlyj30tf0sl7wh.jpg%3FExpires%3D1564330529%26ssig%3DkP54dSRQbD%26KID%3Dimgbed%2Ctva'
    // 小程序二维码
    var urlqCord = 'http://pic.qqtn.com/up/2019-7/2019073010080912409.jpg'

    that.getBG(url).then(function (locationData) {
      that.setData({
        bgpic: locationData
      })
    })
    that.getBG(urll).then(function (locationData) {
      that.setData({
        propic: locationData
      })
    })
    that.getBG(urlqCord).then(function (locationData) {
      that.setData({
        qCord: locationData
      })
    })
  },

  // 点击生成并保持海报到手机相册
  clickMe() {
    var that = this
    that.setData({
      show:true
    })
    that.drawCanvas()
    
  },

  // 绘制canvas
  drawCanvas() {
    var that = this
    var windowW = that.data.windowW
    var windowH = that.data.windowH
    var text = '从不拘泥任何世俗凡人的目光,我要奔向前方那光芒,生而为魔,那又如何'
    // 使用 wx.createContext 获取绘图上下文 context
    var context = wx.createCanvasContext('firstCanvas')

    // 海报背景图
    context.drawImage(that.data.bgpic, (windowW - 280) / 2, (windowH -450) / 2, 280, 450)
    // 商品图片
    context.drawImage(that.data.propic, (windowW -170) / 2, (windowH - 390) / 2, 170,170)
    // 商品文字描述
    context.setFontSize(30)
    context.setFillStyle("red")
    context.fillText('¥99.99', (windowW - 200) / 2, (windowH +55) / 2)
    context.setFontSize(18)
    context.setFillStyle("#999999")
    context.fillText('¥99.99', (windowW + 50) / 2, (windowH +55) / 2)
    context.moveTo((windowW + 45) / 2, (windowH + 44) / 2); //设置线条的起始路径坐标
    context.lineTo((windowW + 200) / 2, (windowH +44) / 2); //设置线条的终点路径坐标
    context.stroke(); //对当前路径进行描边

    // 商品名字,名字很长调用方法将文字折行,传参 文字内容text,画布context
    var row = that.newLine(text, context)
    var a = 24//定义行高25
    for (var i = 0; i < row.length; i++) {
      context.setFontSize(16)
      context.setFillStyle("#000000")
      context.fillText(row[i], (windowW - 195) / 2, (windowH +130)/2 + a * i, 320)
    }

    // 识别小程序二维码
    context.drawImage(that.data.qCord, (windowW - 180) / 2, (windowH + 289) / 2, 75, 75)
    context.setFillStyle("#000000")
    context.setFontSize(12)
    context.fillText('长按识别小程序', (windowW - 0) / 2, (windowH + 350) / 2 )
    context.setFillStyle("#000000")
    context.setFontSize(18)
    context.fillText('享更多好货', (windowW - 0) / 2, (windowH + 390) / 2 )
    context.draw()
  },

  // 点击保存按钮,同时将画布转化为图片
  daochu: function () {
    var that = this;
    wx.canvasToTempFilePath({
      x: 0,
      y: 0,
      canvasId: 'firstCanvas',
      fileType: 'jpg',
      quality: 1,
      success: function (res) {
        that.setData({
          shareImage: res.tempFilePath
        })
        setTimeout(function(){
          wx.showModal({
            title: '提示',
            content: '将生成的海报保存到手机相册,可以发送给微信好友或分享到朋友圈',
            success(res) {
              if (res.confirm) {
                that.eventSave()
              } else if (res.cancel) {
                console.log('用户点击取消')
              }
            }
          })
        },1000)
      }
    })
  },

  // 将商品分享图片保存到本地
  eventSave() {
    wx.saveImageToPhotosAlbum({
      filePath: this.data.shareImage,
      success(res) {
        wx.showToast({
          title: '保存图片成功',
          icon: 'success',
          duration: 2000
        })
      }
    })
  },

  //将线上图片地址下载到本地,此函数进行了封装,只有在需要转换url的时候调用即可
  getBG(url) {
    // Promise函数给我很大的帮助,让我能return出回调函数中的值
    return new Promise(function (resolve) {
      wx.downloadFile({
        url: url, 
        success: function (res) {
          url = res.tempFilePath
          resolve(url);
        }
      })
    })
  },

  // canvas多文字换行
  newLine(txt, context) {
    var txtArr = txt.split('')
    var temp = ''
    var row = []
    for (var i = 0; i < txtArr.length; i++) {
      if (context.measureText(temp).width < 210) {
        temp += txtArr[i]
      } else {
        i--
        row.push(temp)
        temp = ''
      }
    }
    row.push(temp)

    //如果数组长度大于3 则截取前三个
    if (row.length > 3) {
      var rowCut = row.slice(0, 3);
      var rowPart = rowCut[2];
      var test = "";
      var empty = [];
      for (var a = 0; a < rowPart.length; a++) {
        if (context.measureText(test).width < 180) {
          test += rowPart[a];
        } else {
          break;
        }
      }
      empty.push(test);
      var group = empty[0] + "..." //这里只显示三行,超出的用...表示
      rowCut.splice(2, 1, group);
      row = rowCut;
    }

    return row
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
    var that = this
    
  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  }
})

总结:

1、getBG(url)方法:项目中多次进行wx.downloadFile线上图片路径转换成本地路径的方法,为了方便,我将此方法进行封装;

2、使用 Promise函数: 将回调函数中的值进行了return处理,能让外部接收到回调函数的值;

3、解决了canvas绘制的海报在保存到相册的时候出现图片模糊不清,字体有明显锯齿状的情况;

4、newLine(txt, context)方法:解决了画布上多行文字换行功能,并且可以按需设置超过几行后显示省略号;

 

 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
微信小程序通过 Canvas 2D 绘制海报可以用于商品展示、广告宣传等场景。下面介绍一下实现流程: 1. 页面结构 在页面中添加一个 Canvas 标签,设置 id 和宽高: ```html <canvas id="poster" style="width: 750rpx; height: 1334rpx;"></canvas> ``` 2. 获取 Canvas 上下文 在页面的 onLoad 函数中获取 Canvas 上下文: ```javascript let ctx = wx.createCanvasContext('poster'); ``` 3. 绘制背景 使用 Canvas 2D 绘制背景,可以使用 fillRect 方法绘制一个填充矩形: ```javascript ctx.setFillStyle('#ffffff'); ctx.fillRect(0, 0, 750, 1334); ``` 4. 绘制图片 使用 drawImage 方法绘制图片,需要先将图片下载到本地: ```javascript wx.getImageInfo({ src: 'https://example.com/image.png', success: function(res) { ctx.drawImage(res.path, 0, 0, 750, 500); } }); ``` 5. 绘制文本 使用 fillText 或者 strokeText 方法绘制文本,需要设置字体样式和对齐方式: ```javascript ctx.setFontSize(32); ctx.setTextAlign('center'); ctx.fillText('这是一段文本', 375, 600); ``` 6. 保存海报 使用 Canvas 2D 的 toTempFilePath 方法将绘制海报保存到本地: ```javascript ctx.draw(false, function() { wx.canvasToTempFilePath({ x: 0, y: 0, width: 750, height: 1334, canvasId: 'poster', success: function(res) { console.log(res.tempFilePath); } }); }); ``` 完整代码: ```javascript Page({ onLoad: function() { let ctx = wx.createCanvasContext('poster'); ctx.setFillStyle('#ffffff'); ctx.fillRect(0, 0, 750, 1334); wx.getImageInfo({ src: 'https://example.com/image.png', success: function(res) { ctx.drawImage(res.path, 0, 0, 750, 500); } }); ctx.setFontSize(32); ctx.setTextAlign('center'); ctx.fillText('这是一段文本', 375, 600); ctx.draw(false, function() { wx.canvasToTempFilePath({ x: 0, y: 0, width: 750, height: 1334, canvasId: 'poster', success: function(res) { console.log(res.tempFilePath); } }); }); } }); ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值