小程序 自定义二维码 canvas海报 canvas保存为本地图片

Posted 悟空dong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了小程序 自定义二维码 canvas海报 canvas保存为本地图片相关的知识,希望对你有一定的参考价值。

功能很简单 直接上代码

 

html

canvas 定义画板 构造海报  .preview 生成海报图浏览 模板框 

<canvas canvas-id="shareImg" class="canvas-exp"></canvas>
<view hidden=\'{{previewHidden}}\' class=\'preview\'>
  <image src=\'{{preurl}}\' mode=\'widthFix\' class=\'previewImg\'></image>
  <button type=\'primary\' bindtap=\'save\' style="background:#0A655A">保存到本地</button>
</view>
 
<view class="shares-btn">
  <button class="share" bindtap="share">
    <image src="images/icon_share.png" style="width:36rpx;" mode="widthFix"></image>
    <view class="share-title">分享</view>
  </button>
</view>

css


.canvas-exp{
  width:100%;height:606px;background:#fff;
}
.preview {
  width: 100%;
  height: 100%;
  background: rgba(0,0,0,1);
  position:fixed;
  top: 0;
  left: 0;
  z-index: 2;
}
.previewImg{
  width: 88%;
  position: absolute;
  top: 100rpx;
  left: 6%;
  z-index: 3;
  border: 1px solid #000;
  border-radius: 5px;
  max-height: 800rpx;
}
.preview button{
  width: 78%;
  position: absolute;
  top: 960rpx;
  left: 11%;
  border-radius: 2px;
}
.preview .cler{
  width: 64rpx;
  height: 64rpx;
  position: absolute;
  top: 1100rpx;
  left: 50%;
  margin-left: -32rpx;
}
.shares-btn{
  position: fixed;
  right: 20rpx;
  top: 20%;
  z-index: 101;
  transition: all 0.5s;
}
.share{
  width: 100rpx;
  height: 100rpx;
  background-color: #007aff;
  border-radius: 50%;
  color: #fff;
  font-size: 26rpx;
  padding: 0;
}
.share-title{
  margin-top: -14px;
  font-size:24rpx;
}
p{
  padding: 0;
  margin: 0;
}

核心代码 js

 

// pages/all/index.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    currentLineHeight: 0,
    previewHidden: true 
  },
  onLoad(){
    this.createCanvasContext()

  },
  createCanvasContext() {
    let that =this
    var expiration = wx.getStorageSync("index_data_expiration"); //拿到过期时间
    var timestamp = Date.parse(new Date()); //拿到现在时间
    // access_token 过期时间
    if (wx.getStorageSync(\'access_token\') && expiration > timestamp) {
      console.log(wx.getStorageSync(\'access_token\'))
      that.accessToken(wx.getStorageSync(\'access_token\'))
    } else {
      wx.request({
        url: \'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=appid&secret=secret\',
        method: \'get\',
        success: function (ress) {
          wx.setStorageSync("access_token", ress.data.access_token)
          var timestamp = Date.parse(new Date());
          var expiration = timestamp + ress.data.expires_in
          console.log(ress.data.access_token)
          wx.setStorageSync("expires_in", expiration)
          that.accessToken(ress.data.access_token)
        },
        fail: function (res) {
          console.log(res)
        }

      })
    }


  },
  accessToken(access_token) {
    let that = this
 
    let winWidth = wx.getSystemInfoSync().windowWidth; // 获取当前设备的可视宽度
    let winHeight = wx.getSystemInfoSync().windowHeight; // 获取当前设备的可视高度
    that.setData({
      winWidth: winWidth,
      winHeight: winHeight
    })
    let data = {
      page: \'pages/hotinfo/hotinfo\',
      scene: \'12\'
    }
    wx.request({
      url: \'https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=\' + access_token,
      method: \'POST\',
      data: data,
      // dataType: \'json\',
      responseType: \'arraybuffer\', //将返回数据 按文本解析修改为arraybuffer
      success: function (res) {
        console.log(res)
        
        // 利用writeFile bese64图片存本地文件使用
        var imgPath = wx.env.USER_DATA_PATH + \'/tabhome\' + \'ewm\' + \'.png\';
        var fs = wx.getFileSystemManager();
        fs.writeFileSync(imgPath, res.data, "base64");
   
          const ctx = wx.createCanvasContext(\'shareImg\')
          var Rpx = (winWidth / 375).toFixed(2);
         
          ctx.setFillStyle(\'#fff\')
          ctx.fillRect(0, 0, winWidth, 800)

          ctx.drawImage(\'../../\' + res[0].path, 0, 0, winWidth, 228 * Rpx)

          var currentLineHeight = 228 * Rpx + 10;
          ctx.setTextAlign(\'left\')
          ctx.setFillStyle(\'#2E2F2F\')
          ctx.setTextAlign(\'left\')
          let contentTitle = \'世界之大无奇不有,只有不断努力划水才能实现更加有珍贵的,你想要浑浑噩噩的日子,日子才会浑浑噩噩的对待你\'
          var chr = contentTitle.split(""); //这个方法是将一个字符串分割成字符串数组
          var temp = "";
          var row = [];
          for (var a = 0; a < chr.length; a++) {
            if (ctx.measureText(temp).width < winWidth / 2 - 10) {
              temp += chr[a];
            } else {
              a--; 
              row.push(temp);
              temp = "";
            }
          }
          row.push(temp);

          //如果数组长度大于2 则截取前两个
          if (row.length > 2) {
            var rowCut = row.slice(0, 2);
            var rowPart = rowCut[1];
            var test = "";
            var empty = [];
            for (var a = 0; a < rowPart.length; a++) {
              if (ctx.measureText(test).width < winWidth / 2 - 10) {
                test += rowPart[a];
              } else {
                break;
              }
            }
            empty.push(test);
            var group = empty[0] + "..." //这里只显示两行,超出的用...表示
            rowCut.splice(1, 1, group);
            row = rowCut;
          }
          ctx.font = \'normal bold 18px sans-serif\';
          for (var b = 0; b < row.length; b++) {
            currentLineHeight += Rpx * 30;
            ctx.fillText(row[b], 15, currentLineHeight);
          }
          currentLineHeight += 80 * Rpx
          ctx.drawImage(\'../../\' + \'assets/coupon_gold.png\', 20, currentLineHeight, 60 * Rpx, 60 * Rpx)
          currentLineHeight += 35 * Rpx
          ctx.fillText(\'健健康康\', 90 * Rpx, currentLineHeight);
          ctx.drawImage(imgPath, winWidth - 120 * Rpx, currentLineHeight - 70, 100 * Rpx, 100 * Rpx)
          currentLineHeight += 100 - 40 * Rpx
          ctx.stroke()
          ctx.draw()
          that.setData({
            currentLineHeight: currentLineHeight
          })
        })
      }

  },
  save: function () {
    var that = this;
    //获取相册授权
    wx.getSetting({
      success(res) {
        if (!res.authSetting[\'scope.writePhotosAlbum\']) {
          wx.authorize({
            scope: \'scope.writePhotosAlbum\',
            success() {
              that.savaImageToPhoto();
            }
          })
        } else {
          that.savaImageToPhoto();
        }
      }
    })
  },
  /**
   * 生成分享图
   */
  share: function () {
    var that = this
    wx.showLoading({
      title: \'努力生成中...\'
    })

    wx.canvasToTempFilePath({
      x: 0,
      y: 0,
      width: this.data.winWidth,
      height: this.data.currentLineHeight,
      destWidth: this.data.winWidth,
      destHeight: this.data.currentLineHeight,
      canvasId: \'shareImg\',
      success: function (res) {
        console.log(res.tempFilePath);
        that.setData({
          preurl: res.tempFilePath,
          previewHidden: false,
        })
        wx.hideLoading()
      },
      fail: function (res) {
        console.log(res)
      }
    })
  },
  savaImageToPhoto: function () {
    let that = this;
    wx.showLoading({
      title: \'努力生成中...\'
    })
    wx.canvasToTempFilePath({
      x: 0,
      y: 0,
      width: that.data.winWidth,
      height: that.data.winHeight - 70,
      destWidth: that.data.winWidth,
      destHeight: that.data.winHeight - 70,
      canvasId: \'shareImg\',
      success: function (res) {
        console.log(res)
        wx.hideLoading()
        wx.saveImageToPhotosAlbum({
          filePath: res.tempFilePath,
          success(res) {
            wx.showModal({
              content: \'图片已保存到相册\',
              showCancel: false,
              confirmText: \'知道啦\',
              confirmColor: \'#72B9C3\',
              success: function (res) {
                if (res.confirm) {
                  console.log(\'用户点击确定\');
                  that.setData({
                    hidden: true
                  })
                }
              }
            })
          }
        })
      },
      fail: function (res) {
        console.log(res)
      }
    })
  },
})

(https://api.weixin.qq.com接口只能后端请求  不然上线后会出问题 我这边只供体验参考)

本地图片路径错误绘制会失败

1.通过小程序api 接口 https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=appid&secret=secret  (get)

获取 token值  时效两个小时 

2.再通过api 接口 https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=access_token 获取自定义参数的小程序码 (POST)

01.scene 为要携带的参数 最高32位   具体看小程序api文档  接口返回的格式为 arraybuffer

02.请求是注意  参数修改  responseType: \'arraybuffer\', //将返回数据 按文本解析修改为arraybuffer

03.通过api wx.arrayBufferToBase64() 将数据转为bese64   例:

let URL =\'data:image/png;base64,\' + wx.arrayBufferToBase64(res.data)

04.小程序canvas bese64图片 模拟器可正常显示 真机操作则无效  因canvas图片不支持base64 

处理方法为利用writeFile bese64图片存本地文件使用 例:

var imgPath = wx.env.USER_DATA_PATH + \'/tabhome\' + \'ewm\' + \'.png\';

var fs = wx.getFileSystemManager();

fs.writeFileSync(imgPath, res.data, "base64");

wx.env.USER_DATA_PATH 为微信提供无需在意   \'/tabhome\' 为本页面路径 ewm为自定义

writeFileSync内的imgPath为自定义的文件路径 (本地路径) 

writeFileSync内的res.data 为获取到的arraybuffer值 

writeFileSync内的base64 为数据类型

imgPath拿到的 就是本地的图片路径 可直接使用到项目中

3.利用wx.createCanvasContext创建画板 进行绘画 文字太多 自动换行两行省略处理 图片路径一定要正确 不然只会看到空白的canvas

4.利用wx.canvasToTempFilePath() 将canvas截取生成图片  区域可自定义 具体请看官方文档

5.wx.saveImageToPhotosAlbum  保存图片到手机相册

6.注意canvas图片如果是网络图片 要通过 getImageInfo / downloadFile 先下载再使用

流程:

通过canvas提前绘制海报

再通过wx.canvasToTempFilePath() 截取绘制好的海报

最后通过wx.saveImageToPhotosAlbum  保存图片到手机相册

这样就大功告成了

以上是关于小程序 自定义二维码 canvas海报 canvas保存为本地图片的主要内容,如果未能解决你的问题,请参考以下文章

uniapp 手写canvas海报(兼容android/ios/h5/微信小程序)

js 生成海报 可以是png吗

微信小程序-海报制作(canvas)

微信小程序-海报制作(canvas)

小程序 canvas 2d 新接口 绘制带小程序码的海报图

微信小程序canvas画图,保存页面为海报