全网小程序 分享朋友圈canvas生成海报,保存到相册

3,171 阅读3分钟

做这个分享海报真的遇到一个让我深刻的问题,就是在绘制圆的时候出来的黑色边框的问题,真是搞的头痛死了,花了一下午的时候找资料,没有解决,后面跟朋友在聊这个问题的时候,在看网上案例,还是自己对canvas不熟悉的原因,才迟迟没有解决这个问题,所以我在这里记录一下,希望有可能帮忙有需求的朋友们!觉得有帮忙的朋友,麻烦点个赞,支持一下我,谢谢了

这里要感谢一下 IT小智朋友分享出来的文章,我是按照他的方法生成海报

文章地址 blog.csdn.net/zhihui1017/…

首先看一下最终效果图

html

<view class="canvasBg" wx:if="{{canvasSwith}}" catchtouchmove="ture">
    <view class="canvasWaip">
      <view class="canvas_con">
        <view class="con_l">
          <view class="canvas_ani">
            <canvas canvas-id="shareCanvas" style="width:253px;height:317px" bindlongtap='saveCanvas'></canvas>
          </view>
        </view>
        <view class="vas_cal" catchtap="posterTab" data-id="2">
          <wux-icon type="ios-close" color="#666" />
        </view>
      </view>
      <view class="canvasText">
        <text>保存图片后,可分享至朋友圈</text>
      </view>
      <view class="canvasBtn" catchtap="saveCanvas">
        <view class="btn_save">
          <text>保存</text>
        </view>
      </view>
    </view>
  </view>	

css

.canvasBg{
  width: 100%;
  height: 100vh;
  background: rgba(0, 0, 0, .5);
  position: fixed;
  top: 0;
  left: 0;
}
.canvasWaip{
  position: fixed;
  width: 100%;
  background: #fff;
  bottom: 0;
  left: 0;
  padding: 20rpx 0;
}
.canvasWaip .canvas_con{
  width: 100%;
  display: flex;
  flex-direction: column;
  /* margin-top: 20rpx; */
  position: relative;
}
.canvas_con .con_l{
  /* width: 460rpx; */
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  box-shadow: 0px 2px 15rpx 0px rgba(6, 0, 1, 0.1);
  border-radius: 15rpx;
  overflow: hidden;
}
.canvasWaip .canvas_con .con_l .canvas_ani{
  /* width: 460rpx; */
  /* height: 575rpx; */
}
.canvasWaip .canvas_con .vas_cal{
  width: 60rpx;
  position: absolute;
  right: 0rpx;
  top: 0rpx;
}
.canvasBtn{
  display: flex;
  flex-direction: row;
  justify-content: center;
  height: 100rpx;
  /* margin-top: 20rpx; */
  align-items: center;
}
.canvasBtn .btn_save{
  width: 324rpx;
  height: 70rpx;
  background: linear-gradient(90deg, #45A6E9 0%, #51F4EE 100%);
  border-radius: 35rpx;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
.canvasBtn .btn_save text{
  font-size: 30rpx;
  color: #fff;
  font-weight: bold;
}
.canvasBtn  .btn_cal{
  width: 70rpx;
}
.canvasWaip .canvasText{
  text-align: center;
  font-size: 28rpx;
  font-weight: bold;
  margin-top: 20rpx;
}

说一下前面说了为什么绘制圆的时候会出现黑色边框的原因就是, ctx.stroke() 原因, 这个要绘制 ctx.arc圆之后就ctx.setStrokeStyle然后就是ctx.stroke(),之前把ctx.stroke()放到最后,才会出现黑色边框的问题!

分享的二维码是通过请求接口拿到的

js

// 获取分享二维码
  getWxArticleShareQrcode(id) {
    let articleId = id
    api.getWxArticleShareQrcode({
      data: {
        scene: 'articleId=' + articleId,
        page: 'pages/index/index',
        articleId
      },
      success: res => {
        let cavvasUrl =  res.url
        console.log('Qrcode', cavvasUrl)
        if(res.code == -1) {
          util.showToast(res.message,2)
        } else {
          this.setData({
            cavvasUrl
          })
        }
      }
    })
  },
  
  // 绘制分享海报
  wxGetCanvasImage() {
    util.showLoading()
    let cavvasUrl = this.data.cavvasUrl
    let cardUser = this.data.cardUser
    let title = this.data.list.title
    console.log('title', title.length)
    const wxGetImageInfo = util.promisify(wx.getImageInfo)
    Promise.all([
        wxGetImageInfo({
            src: 'http://ytdev.cn-gd.ufileos.com/image/yh/wit21.png'
        }),
        wxGetImageInfo({
          src: cardUser.headPortrait
      }),
        wxGetImageInfo({
            src: cavvasUrl
        })
    ]).then(res => {
      util.hideLoading()
      console.log('res',res)
        const ctx = wx.createCanvasContext('shareCanvas')
        
        // 底图
        ctx.drawImage(res[0].path, 0, 0, 253, 317)
    
        // 作者名称
        ctx.setTextAlign('left')    // 文字居中
        ctx.setFillStyle('#000000')  // 文字颜色:黑色
        ctx.setFontSize(14)         // 文字字号:22px
        ctx.fillText(cardUser.userName, 60, 155)

        if(title.length>16) {
          console.log('title.length大于8')
          let title1 = title.slice(0,15)
          let title2 = title.slice(15, title.length)
          // 标题1
          ctx.setTextAlign('left')    // 文字居中
          ctx.setFillStyle('#666')  // 文字颜色:黑色
          ctx.setFontSize(14)         // 文字字号:22px
          ctx.fillText(title1, title.length*1, 200)
          // 标题
          ctx.setTextAlign('left')    // 文字居中
          ctx.setFillStyle('#666')  // 文字颜色:黑色
          ctx.setFontSize(14)         // 文字字号:22px
          ctx.fillText(title2, title.length*1, 220)
        } else {
          // 标题1
          ctx.setTextAlign('left')    // 文字居左
          ctx.setFillStyle('#666')  // 文字颜色:黑色
          ctx.setFontSize(14)         // 文字字号:22px
          if(title.length<5) {
            console.log('title.length小于5')
            ctx.fillText(title, title.length*3, 220)
          } else {
            ctx.fillText(title, title.length*1, 220)
          }
          
        }
    
        // 头像
        ctx.save()
        //绘制专属头像;
        ctx.beginPath()
        
        // 圆的圆心的 x 坐标和 y 坐标,25 是半径,后面的两个参数就是起始和结束,这样就能画好一个圆了
        ctx.arc(30, 150, 20, 0, 2 * Math.PI,false)
        // 下面就裁剪出一个圆形了,且坐标在 (paddingWidth + 25, paddingWidth + 25)
        ctx.setStrokeStyle('#ffffff')
        ctx.stroke()
        ctx.clip()
        
        ctx.drawImage(res[1].path, 10,130, 40, 40)
        ctx.restore()

        // 小程序码
        ctx.drawImage(res[2].path, 20,250, 60, 60)
        // 小程序码描述
        ctx.setTextAlign('left')    // 文字居中
        ctx.setFillStyle('#999')  // 文字颜色:黑色
        ctx.setFontSize(14)         // 文字字号:22px
        ctx.fillText("长按小程序码查看详情", 90, 270)
        // 小程序码描述
        ctx.setTextAlign('left')    // 文字居中
        ctx.setFillStyle('#999')  // 文字颜色:黑色
        ctx.setFontSize(14)         // 文字字号:22px
        ctx.fillText("分享自 【趣联日记】", 90, 290)
    
        
        ctx.draw()
    })
  },
  // 保存分享海报
  saveCanvas() {
    const wxCanvasToTempFilePath = util.promisify(wx.canvasToTempFilePath)
    const wxSaveImageToPhotosAlbum = util.promisify(wx.saveImageToPhotosAlbum)
    wxCanvasToTempFilePath({
      canvasId: 'shareCanvas'
    }, this).then(res => {
        return wxSaveImageToPhotosAlbum({
            filePath: res.tempFilePath
        })
    }).then(res => {
        wx.showToast({
            title: '已保存到相册'
        })
        this.setData({
          canvasSwith: false
        })
    })
  },

util.js promisify方法

// Canvas绘制海报
const promisify = (api) => {
  return (options, ...params) => {
    return new Promise((resolve, reject) => {
      const extras = {
        success: resolve,
        fail: reject
      }
      api({ ...options, ...extras }, ...params)
    })
  }
}
module.exports = {
	promisify
}

总结一下

开发这个功能,总共花了差不多一天时间吧,关于哪个黑色边框问题,一个下午多的时间才解决,我也是第一次做分享海报,没经验,对canvas也不熟悉,定位不了问题出在哪里,只能花大量的时间去查资料,看别人分享出来的案例,后面我又花了下班后花二个小时看canvas基础视频,还是没有解决,后面还是通过在群里问群友和朋友,有一个热心的朋友回答我的问题,聊着聊着,自己也慢慢的静下心来,仔细的检查一下代码,最终发现了一个问题,跟网友分享的不一样,抱着试试的态度,没想到可以了,解决了这个问题,后面又去查了资料,才知道原因,

说实话这个问题真很搞心态,在搞不定就只能跟设计说,不要圆形头像了,谢天谢地,这个问题还是解决了。

感谢一路帮助我的朋友了,谢谢您们