微信小程序生成海报并保存到本地(附带二维码生成)

小程序端刚刚拿到了一个新的需求说要生成一张海报 用户保存图片到本地分享,话不多说直接上代码

/ pages/haibao/haibao.js
Page({
 
  /**
   * 页面的初始数据
   */
  data: {
    evalatImage:'',
    bgBanner:'',
    imagePath:"",
    maskHidden:false,
    qrcode_image:''
  },
 
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
 
  },
 
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
 
  },
 
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    var  that = this;
    wx.getImageInfo({
      src: "https://m.xinjuenet.com/images/banner/b-xldh.jpg",
      success(res) {
        console.log("banner临时路径:" + res.path);
        that.setData({
          evalatImage: res.path
        })
      }
    })
    wx.getImageInfo({
      src: "https://m.xinjuenet.com/images/banner/b-xldh.jpg",
      success(res) {
        console.log("海报底部背景:" + res.path);
        that.setData({
          bgBanner: res.path
        })
      }
    })
    that.qrcode_image();
    wx.getImageInfo({
      src: that.data.qrcode_image,
      success(res) {
        console.log("二维码:" + res.path);
        that.setData({
          qrcode_image: res.path
        })
      }
    })
  },
 
  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {
 
  },
 
  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {
 
  },
 
  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {
 
  },
 
  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
 
  },
 
  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {
 
  },
  //点击生成海报
  formSubmit: function (e) {
    var that = this;
    wx.showToast({
      title: '海报生成中...',
      icon: 'loading',
      duration: 1000
    });
    that.createNewImg();
    setTimeout(function () {
      wx.hideToast()
      that.setData({
        maskHidden: true
      });
    }, 1000);
  },
  //将canvas转换为图片保存到本地,然后将图片路径传给image图片的src
  createNewImg: function () {
    var that = this;
    var context = wx.createCanvasContext('mycanvas');
    context.clearRect(0, 0, 375, 660);
    context.setFillStyle("#fff")
    context.fillRect(0, 0, 375, 660)
    context.save();
 
    var path = that.data.evalatImage;
    context.drawImage(path, 0, 0, 375, 183);
 
 
    var path1 = that.data.bgBanner;
    console.log("海报底部背景图" + path1);
    var path2 = that.data.qrcode_image;
    console.log("海报底部二维码" + path2);
    context.setFontSize(16);
    context.setFillStyle('#333');
    context.setTextAlign('left');
    context.fillText("测试结果", 60, 230);
    context.stroke();
    context.save();
 
    var titl = "分享标题";
    context.setFontSize(18);
    context.setFillStyle('#333');
    context.setTextAlign('left');
    context.font = 'normal bold 18px sans-serif';
    context.fillText(titl, 60, 270);
    context.stroke();
    context.save();
 
 
 
    context.setFontSize(16);
    context.setFillStyle('#333');
    context.setTextAlign('left');
    context.fillText("测试说明", 60, 320);
    context.stroke();
    context.save();
    context.drawImage(path1, 0, 550, 375, 130);
 
    var results = "分享的文本信息,布上下文 canvasID";
 
    // 测试结果说明
    that.dealWords({
      ctx: context,                     //画布上下文 canvasID
      fontSize: 16,                //字体大小
      word: results,                  //需要处理的文字
      maxWidth: 270,             //一行文字最大宽度
      x: 60,                    //文字在x轴要显示的位置
      y: 340,                      //文字在y轴要显示的位置
      maxLine: 6              //文字最多显示的行数
    });
    context.stroke();
    context.save(); //保存之前的画布设置
 
    //绘制头像
    context.beginPath();
    context.arc(50, 225, 5, 0, 2 * Math.PI);
    context.setStrokeStyle("#c7eddd");
    context.setFillStyle("#44bf8c");
    context.clip(); //裁剪上面的圆形
    context.fill();//填充
    context.restore();//因为clip是剪切了画布  则后面所有的操作都会限制在被裁减的区域内可见  用restore可以恢复之前的设置
    context.closePath();
 
    context.save(); //保存之前的画布设置
    context.beginPath();
    context.arc(50, 315, 5, 0, 2 * Math.PI);
    context.setStrokeStyle("#c7eddd");
    context.setFillStyle("#44bf8c");
    context.clip(); //裁剪上面的圆形
    context.fill();//填充
    context.restore();
    context.closePath();
 
    context.save(); //保存之前的画布设置
    context.beginPath();
    context.arc(55, 610, 50, 0, 2 * Math.PI);
    context.setStrokeStyle("#ffe200");
    context.clip(); //裁剪上面的圆形
    context.drawImage(path2, 5, 560, 100, 100);
    context.restore();
    context.closePath();
 
    context.save(); //保存之前的画布设置
    context.beginPath();
    // context.setFontSize(16);
    context.setFillStyle('#fff');
    context.setTextBaseline("top");
    context.setTextAlign('left');
    // context.font = 'normal 18px arial';
    // context.fillText("预防疫情四大宅家心理健康测评", 115, 565);
    // context.fillText("预防疫情四大宅家心理健康测评", 115, 589);
    that.dealWords({
      ctx: context,                     //画布上下文 canvasID
      fontSize: 16,                //字体大小
      word: titl,                 //需要处理的文字
      maxWidth: 240,             //一行文字最大宽度
      x: 115,                   //文字在x轴要显示的位置
      y: 540,                      //文字在y轴要显示的位置
      maxLine: 2              //文字最多显示的行数
    });
    context.stroke();
    context.closePath();
    context.save(); //保存之前的画布设置
    context.draw(true);//true表示保留之前绘制内容
 
 
    //将生成好的图片保存到本地,需要延迟一会,绘制期间耗时
    setTimeout(function () {
      wx.canvasToTempFilePath({
        canvasId: 'mycanvas',
        success: function (res) {
          var tempFilePath = res.tempFilePath;
          that.setData({
            imagePath: tempFilePath
          });
        },
        fail: function (res) {
          console.log(res);
        }
      });
    }, 1000);
  },
  //文本换行
  dealWords(options) {
    options.ctx.setFontSize(options.fontSize);//设置字体大小
    var allRow = Math.ceil(options.ctx.measureText(options.word).width / options.maxWidth);//实际总共能分多少行
    var count = allRow >= options.maxLine ? options.maxLine : allRow;//实际能分多少行与设置的最大显示行数比,谁小就用谁做循环次数
 
    var endPos = 0;//当前字符串的截断点
    for (var j = 0; j < count; j++) {
      var nowStr = options.word.slice(endPos);//当前剩余的字符串
      var rowWid = 0;//每一行当前宽度    
      if (options.ctx.measureText(nowStr).width > options.maxWidth) {//如果当前的字符串宽度大于最大宽度,然后开始截取
        for (var m = 0; m < nowStr.length; m++) {
          rowWid += options.ctx.measureText(nowStr[m]).width;//当前字符串总宽度
          if (rowWid > options.maxWidth) {
            if (j === options.maxLine - 1) { //如果是最后一行
              options.ctx.fillText(nowStr.slice(0, m - 1) + '...', options.x, options.y + (j + 1) * 25);    //(j+1)*20这是每一行的高度        
            } else {
              options.ctx.fillText(nowStr.slice(0, m), options.x, options.y + (j + 1) * 25);
            }
            endPos += m;//下次截断点
            break;
          }
        }
      } else {//如果当前的字符串宽度小于最大宽度就直接输出
        options.ctx.fillText(nowStr.slice(0), options.x, options.y + (j + 1) * 25);
      }
    }
  },
  //点击保存到相册
  baocun: function () {
    var that = this
    wx.saveImageToPhotosAlbum({
      filePath: that.data.imagePath,
      success(res) {
        wx.showModal({
          content: '图片已保存到相册,赶紧晒一下吧~',
          showCancel: false,
          confirmText: '好的',
          confirmColor: '#333',
          success: function (res) {
            if (res.confirm) {
              console.log('用户点击确定');
              /* 该隐藏的隐藏 */
              that.setData({
                maskHidden: false
              })
            }
          }, fail: function (res) {
            console.log(11111)
          }
        })
      }
    })
  },
  qrcode_image: function () {
    let that = this;
    wx.request({
      url: 'https://api.weixin.qq.com/cgi-bin/token',
      data: {
        grant_type: 'client_credential',
        appid: '你的APPID', //不能缺少
        secret: '你的APPID秘钥' //不能缺少
      },
      success: function (res) {
        wx.request({
          url: 'https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=' + res.data.access_token,
          data: {
            "path": "pages/index/index", //默认跳转到主页:pages/index/index,可指定
            "width": 200,
            "scene": "type=0&evaId=" + that.data.id,
          },
          responseType: 'arraybuffer', // 这行很重要,转为二进制数组
          header: {
            'content-type': 'application/json;charset=utf-8'
          },
          method: 'POST',
          success(res) {
            //转为base64
            let bin64 = wx.arrayBufferToBase64(res.data);
 
            that.setData({
              //base 64设置到页面上
              qrcode_image: "data:image/png;base64," + bin64
            });
          }
        })
      }
    })
  }
})






下面是页面代码

<!--pages/haibao/haibao.wxml-->
 
<button bindtap="formSubmit">点击生成海报</button>
 
<view class='imagePathBox' hidden="{{maskHidden == false}}">
    <image src="{{imagePath}}" class='shengcheng' ></image>
    <button class='baocun' bindtap='baocun'>点击保存至相册,分享到朋友圈</button>
</view>
<view hidden="{{maskHidden == false}}" class="mask"></view> 
<view class="canvas-box">
    <canvas  style="width:375px;height:670px;position:fixed;top:9999px" canvas-id="mycanvas"/>
</view>  

下面也发一下样式文件

/* pages/mentality/result/result.wxss */
page{ background:#fff;}
 
 
.imagePathBox{
  width: 100%;
  height: 100%;
  background: rgba(0,0,0,0.7);
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 9999;
}
.mask{
  width: 100%;
  height: 100%;
  /* background: rgba(0,0,0,0.7); */
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 9000;
}
.shengcheng{
  width: 80%;
  height: 80%;
  position: fixed;
  top: 50rpx;
  left: 50%;
  margin-left: -40%;
  z-index: 10;
}
.baocun{
  display: block;
  width: 80%;
  height: 80rpx;
  padding: 0;
  line-height: 80rpx;
  text-align: center;
  position: fixed;
  bottom: 50rpx;
  left: 10%;
  background: #45be8d;
  color: #fff;
  font-size: 32rpx;
  border-radius: 44rpx;
}
 
.shareFriends{
  display: block;
  width: 80%;
  height: 104rpx;
  padding: 0;
  line-height: 80rpx;
  text-align: center;
  position: fixed;
  bottom: 50rpx;
  left: 10%;
  background: #45be8d;
  color: rgb(211, 208, 208);
  font-size: 32rpx;
  border-radius: 44rpx;
}
 
 
button[class="baocun"]::after{
  border: 0;
}
 
/* canvas绘图 */
/* .canvas-box{
  width:0rpx;
  height:0rpx;
  overflow: hidden;
  position: fixed;
  left:0rpx;
  bottom:30rpx;
  z-index: 9999;
} */
 

效果图来一张

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