小程序 生成自定义小程序二维码码 通过 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>

<button class='shares' type='primary' bindtap='share'>生成成绩单</button>

css

.shares{

  position: absolute;

  bottom: 100rpx;

  width: 70%;

  left: 15%;

  height: 100rpx;

  line-height: 100rpx;

}

.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;

}

核心代码 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  保存图片到手机相册

流程:

通过canvas提前绘制海报

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

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

这样就大功告成了


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342