在微信小程序使用canvas生成海報,並保存圖片在本地


目標:在微信小程序中頁面有一個按鈕,點擊后生成一張海報,點擊保存,圖片保存到本地相冊

海報樣式如下:

 

 通過觀摩別人代碼,分析這張海報,難點有四個,一是背景的圓角,canvas並沒有一個api是畫圓角的,二是中間的兩行標題,這里應該是動態的,可能一行可能兩行,三是圓形頭像處理,四是,畫出的海報如何在點擊下載的時候很好的布局。最終成果如下:

 wxml:

<view class="btn" bindtap="share">點我生成海報</view>
<canvas canvas-id="firstCanvas" class="canvas-exp"></canvas>
<view hidden='{{previewHidden}}' class='preview'>
  <image src='{{preurl}}' mode='widthFix' class='previewImg' style="height:{{currentLineHeight}}px"></image>
  <button bindtap='eventSave' class="btnSave">保存到相冊</button>
</view>

wxss:

.btn {
  text-align: center;
  margin-top: 300rpx;
}


.btnSave {
  width: 408rpx;
  height: 92rpx;
  line-height: 92rpx;
  background: #FFFFFF;
  border-radius: 46rpx;
  text-align: center;
  font-size: 36rpx;
  font-weight: 600;
  color: #FF6C5D;
  margin-top:30rpx;
}

.preview{
  width: 100%;
  height: 100%;
  background: rgba(0,0,0,0.7);
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 10;
}

.canvas-exp {
  position: fixed;
  bottom: 0;
  right: 100%;
  width: 100%;
  height: 100%;
  background: transparent;
}

.previewImg {
  width: 560rpx;
  border-radius:56rpx;
  margin-top: 64rpx;
  margin-left:12.8%;
}

js中的data:

data: {
    windowW: 0,
    windowH: 0,
    show: false,
    bgpic: '',
    propic: '',
    qCord: '',
    picImg: '',
    previewHidden: true,
    preurl: '',
    currentLineHeight:0
  },

js中的onLoad:

onLoad: function (options) {
    let that = this
    // 獲取設備寬高
    wx.getSystemInfo({
      success: function (res) {
        that.setData({
          windowW: res.windowWidth,
          windowH: res.windowHeight
        })
      }
    })
    that.setData({
      bgpic: '../../../assets/head.png',
      propic: '../../../assets/postbg.png',
      qCord: '../../../assets/code.png',
      picImg: '../../../assets/backImg.png'

    })
    that.drawCanvas()
  }

在onLoad,海報中的圖片資源應該是動態的可以在這請求好,在這邊已經生成海報,考慮海報在點擊以后再去生成要等待時間過長,圖片資源下載失敗還可以在頁面加載之后再去請求。

canvas繪制海報函數:

  drawCanvas() {
    let that = this
    let windowW = that.data.windowW
    let windowH = that.data.windowH
    let ctx = wx.createCanvasContext('firstCanvas')
    let text = '健康大使就發生了的打掃房間了放大設計方案放大鏡雙方就安分'
    let row = []
    let strLen = text.length
    let rowNum = 0
    // 計算文字行數
    row.push(text.slice(0, 12))
    rowNum = 1
    if (strLen > 12 && (strLen <= 24)) {
      rowNum = 0
      row.push(text.slice(12, 24))
    }
    if (strLen > 24) {
      rowNum = 0
      row.push(text.slice(12, 22) + '...')
    }

    ctx.drawImage(that.data.propic, (windowW - 279) / 2, 32, 279, (460 - rowNum * 26))
    that.setData({
      currentLineHeight: 460 - rowNum * 26
    })
    ctx.setFillStyle('#FFFFFF')
    // 白色圓角背景
    let x = (windowW - 256) / 2
    let y = 62
    let r = 24
    let w = 256
    let h = 344 - rowNum * 26
    ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5)
    ctx.moveTo(x + r, y)
    ctx.lineTo(x + w - r, y)
    ctx.lineTo(x + w, y + r)
    ctx.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2)
    ctx.lineTo(x + w, y + h - r)
    ctx.lineTo(x + w - r, y + h)
    ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5)
    ctx.lineTo(x + r, y + h)
    ctx.lineTo(x, y + h - r)
    ctx.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI)
    ctx.lineTo(x, y + r)
    ctx.lineTo(x + r, y)
    ctx.fill()

    // 識別小程序二維碼
    ctx.drawImage(that.data.qCord, (windowW - 236) / 2 + 173, 32 + 387, 60, 60)
    ctx.setFillStyle("#ffffff")
    ctx.setFontSize(13)
    ctx.fillText('長按識別二維碼', (windowW - 236) / 2, 32 + 412 - rowNum * 26)
    ctx.setFillStyle("#ffffff")
    ctx.setFontSize(13)
    ctx.fillText('查看TA發布的全部精華內容', (windowW - 236) / 2, 32 + 433 - rowNum * 26)
    ctx.setFillStyle("#0B0D0E")
    ctx.setFontSize(15)
    ctx.fillText('健康醫生', (windowW - 218) / 2 + 48, 32 + 345 - rowNum * 26)

    let collectImg = '../../../assets/hexagon.png'
    ctx.drawImage(collectImg, (windowW - 218) / 2, 92, 18, 20)
    ctx.font = 'normal bold 14px PingFang-SC-Medium';
    ctx.setFillStyle("#AF8B43")
    ctx.fillText('精選內容', (windowW - 218) / 2 + 24, 108)
    ctx.drawImage(that.data.picImg, (windowW - 218) / 2, 32 + 160 - rowNum * 26, 213, 136)

    // 圓形頭像
    let avatarurl_width = 38
    let avatarurl_heigth = 38
    let avatarurl_x = (windowW - 218) / 2
    let avatarurl_y = 352 - rowNum * 26
    ctx.save()
    ctx.beginPath()
    ctx.arc(avatarurl_width / 2 + avatarurl_x, avatarurl_heigth / 2 + avatarurl_y, avatarurl_width / 2, 0, Math.PI * 2, false)
    ctx.clip()
    ctx.drawImage(that.data.bgpic, avatarurl_x, avatarurl_y, avatarurl_width, avatarurl_heigth)
    ctx.restore()
    for (let b = 0; b < row.length; b++) {
      ctx.font = 'normal bold 22px PingFang-SC-Medium';
      ctx.setFillStyle("#0B0D0E")
      ctx.fillText(row[b], (windowW - 218) / 2, 144 + b * 26, 218)
    }
    ctx.draw()
  },

由於標題數據動態,不知道是一行還是兩行,如果超過兩行只顯示兩行,且以省略號結尾,這會導致整張海報的高度發生改變,整個布局都會受影響,因而先計算標題行數。若先繪制標題,會被后面的白色背景覆蓋,后文的文字也會帶上標題的加粗等樣式,所以放在了最后面。

點擊生成海報,把海報轉成圖片顯示在頁面:

  share: function () {
    var that = this
    wx.showLoading({
      title: '努力生成中...'
    })
    wx.canvasToTempFilePath({
      x: (that.data.windowW - 279) / 2,
      y: 32,
      width: 279,
      height: that.data.currentLineHeight,
      canvasId: 'firstCanvas',
      fileType: 'jpg',
      quality: 1,
      success: function (res) {
        console.log(res.tempFilePath);
        that.setData({
          preurl: res.tempFilePath,
          previewHidden: false,
        })
        wx.hideLoading()
      },
      fail: function (res) {
        console.log(res)
      }
    })
  }

本來設計頁面是點擊生成海報,canvas跟保存海報按鈕放在灰色背景上,但是在不同的設備下,保存海報按鈕跟海報距離相差太大,因而改成頁面加載,在可視范圍之外把canvas畫好,點擊生成海報時,只是把海報轉成圖片,變成圖片和按鈕的布局

點擊保存海報:

  eventSave() {
    let that =this
    wx.saveImageToPhotosAlbum({
      filePath: this.data.preurl,
      success(res) {
        wx.showToast({
          title: '保存圖片成功',
          icon: 'success',
          duration: 2000
        })
        that.setData({
          previewHidden: true,
        })
      }
    })
  }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM