微信小程序利用canvas生成海报分享图片

一 . 效果

 这是借用女神照生成的分享的海报,图片来自网络。

新增了poster组件和更新图片自适应

二 . 准备

 准备两张图片连接,最好是自己开发账号验证的https图片链接。

三 . 实现思路

其实就是canvas实现方式,首先要就是定义一个canvas容器,把容器放在中间,图片也要动态计算大小居中,显示下面的文字和二维码也是要根据容器动态去改变,这就是大概的实现思路。

四 . 实现代码

利用微信小程序canvas生成海报分享图片,这个生成图片排版和适配不同尺寸的手机是一个难点,特别是图片适应问题,我处理的方法是动态获取容器的宽度进行适应就是利用微信API wx.createSelectorQuery(),不知道还有没有更好的办法可以请教。

1.下载头像
为了确保图片下载完成之后,再回调其它方法执行下一步。

  getAvaterInfo: function (cardInfo) {//cardInfo是传入的信息参数,按实际需要。
    wx.showLoading({ title: '生成中...',mask: true,});
    var that = this;
    if (cardInfo.CardInfo.Avater) {
      wx.downloadFile({
        url: '图片路径',
        success: function (res) {
          wx.hideLoading();
          if (res.statusCode === 200) {
            var avaterSrc = res.tempFilePath;
            that.getQrCode(avaterSrc, cardInfo);
          }else{
            wx.showToast({
              title: '头像下载失败!',
              icon:'none',
              duration: 2000,
              success:function(){
                that.getQrCode(avaterSrc = "", cardInfo);//回调另一个图片下载
              }
            })
          }
        }
      })
    } else {
      wx.hideLoading();
      that.getQrCode(avaterSrc = "", cardInfo);//回调另一个图片下载
    }
  },

2.下载二维码
二维码下载一样的道理,就是先下载完成,再进行绘图。

  getQrCode: function (avaterSrc, cardInfo) {
    wx.showLoading({ title: '生成中...', mask: true, });
    var that = this;
    if (cardInfo.CardInfo.QrCode) {
      wx.downloadFile({
        url: cardInfo.CardInfo.QrCode,
        success: function (res) {
          wx.hideLoading();
          if (res.statusCode === 200) {
            var codeSrc = res.tempFilePath;
            that.sharePosteCanvas(cardInfo, avaterSrc, codeSrc);//真正的绘图方法
          } else {
            wx.showToast({
              title: '二维码下载失败!',
              icon: 'none',
              duration: 2000,
              success: function () {
                var codeSrc  = "";
                that.sharePosteCanvas(cardInfo, avaterSrc, codeSrc);//真正的绘图方法
              }
            })
          }
        }
      })
    } else {
      wx.hideLoading();
     var codeSrc  = "";
      that.sharePosteCanvas(cardInfo, avaterSrc, codeSrc);//真正的绘图方法
    }
  },

3.绘制分享海报
这里才是canvas实现绘制的过程

  sharePosteCanvas: function (cardInfo, avaterSrc, codeSrc) {
    wx.showLoading({
      title: '生成中...',
      mask: true,
    })
    var that = this;
    const ctx = wx.createCanvasContext('myCanvas');
    var width = "";
    wx.createSelectorQuery().select('#canvas-container').boundingClientRect(function (rect) {
      var height = rect.height;
      var right = rect.right;
      width = rect.width * 0.8;
      var left = rect.left + 5;
      ctx.setFillStyle('#fff');
      ctx.fillRect(0, 0, rect.width, height);

      //头像
      if (avaterSrc) {
        ctx.drawImage(avaterSrc, left, 20, width, width);
        ctx.setFontSize(14);
        ctx.setFillStyle('#fff');
        ctx.setTextAlign('left');
      }

      if (cardInfo.TagList.length > 0) {
        ctx.fillText(cardInfo.TagList[0].TagName, left + 20, width - 4); //标签
        const metrics = ctx.measureText(cardInfo.TagList[0].TagName); //测量文本信息
        ctx.stroke();
        ctx.rect(left + 10, width - 20, metrics.width + 40, 25);
        ctx.setFillStyle('rgba(255,255,255,0.4)');
        ctx.fill();
      }

      if (cardInfo.CardInfo.Name) {
        ctx.setFontSize(14);
        ctx.setFillStyle('#000');
        ctx.setTextAlign('left');
        ctx.fillText(cardInfo.CardInfo.Name, left, width + 60); //姓名
      }

      if (cardInfo.CardInfo.Position) {
        ctx.setFontSize(12);
        ctx.setFillStyle('#666');
        ctx.setTextAlign('left');
        ctx.fillText(cardInfo.CardInfo.Position, left, width + 85); //职位
      }

      if (cardInfo.CardInfo.Mobile) {
        ctx.setFontSize(12);
        ctx.setFillStyle('#666');
        ctx.setTextAlign('left');
        ctx.fillText(cardInfo.CardInfo.Mobile, left, width + 105); //电话
      }

      if (cardInfo.CardInfo.Company) {
        // 公司名称
        const CONTENT_ROW_LENGTH = 24; // 正文 单行显示字符长度
        let [contentLeng, contentArray, contentRows] = that.textByteLength(cardInfo.CardInfo.Company, CONTENT_ROW_LENGTH);
        ctx.setTextAlign('left');
        ctx.setFillStyle('#000');
        ctx.setFontSize(10);
        let contentHh = 22 * 1;
        for (let m = 0; m < contentArray.length; m++) {
          ctx.fillText(contentArray[m], left, width + 150 + contentHh * m);
        }
      }

      //  绘制二维码cardInfo.CardInfo.QrCode
      if (codeSrc) {
        ctx.drawImage(codeSrc, left + 150, width + 40, width / 3, width / 3)
        ctx.setFontSize(10);
        ctx.setFillStyle('#000');
        ctx.setTextAlign('right');
        ctx.fillText("微信扫码或长按识别", left + 235, width + 150);
      }

    }).exec()

    setTimeout(function () {
      ctx.draw();  这里有个需要注意就是,这个方法是在绘制完成之后在调用,不然容易其它被覆盖。
      wx.hideLoading();
    }, 1000)

  },

4.多行显示文字
这个函数就是需要多行显示文字的时候进行折行,就是切分为数组。

  textByteLength(text, num) { // text为传入的文本  num为单行显示的字节长度
    let strLength = 0; // text byte length
    let rows = 1;
    let str = 0;
    let arr = [];
    for (let j = 0; j < text.length; j++) {
      if (text.charCodeAt(j) > 255) {
        strLength += 2;
        if (strLength > rows * num) {
          strLength++;
          arr.push(text.slice(str, j));
          str = j;
          rows++;
        }
      } else {
        strLength++;
        if (strLength > rows * num) {
          arr.push(text.slice(str, j));
          str = j;
          rows++;
        }
      }
    }
    arr.push(text.slice(str, text.length));
    return [strLength, arr, rows] //  [处理文字的总字节长度,每行显示内容的数组,行数]
  },

5.保存绘制生成图片
这一步就是最后把canvas生成图片了,大功告成。

  //点击保存到相册
  saveShareImg: function () {
    var that = this;
    wx.showLoading({
      title: '正在保存',
      mask: true,
    })
    setTimeout(function () {
      wx.canvasToTempFilePath({
        canvasId: 'myCanvas',
        success: function (res) {
          wx.hideLoading();
          var tempFilePath = res.tempFilePath;
          wx.saveImageToPhotosAlbum({
            filePath: tempFilePath,
            success(res) {
              wx.showModal({
                content: '图片已保存到相册,赶紧晒一下吧~',
                showCancel: false,
                confirmText: '好的',
                confirmColor: '#333',
                success: function (res) {
                  if (res.confirm) { }
                },
                fail: function (res) { }
              })
            },
            fail: function (res) {
              wx.showToast({
                title: res.errMsg,
                icon: 'none',
                duration: 2000
              })
            }
          })
        }
        });
          }, 1000);
       },

五 . 填坑

1.图片要提前下载
这里面还有一个问题就是,图片要提前下载完之后再绘图,不然图片显示不出来,可以把下载图片的方法单独拎出来,然后下载图片后回调绘图方法。

  1. ctx.draw()
    这个方法是在绘制完成之后在调用,不然容易其它被覆盖。

这样就大功告成了,有问题可以和联系作者,一起进步。
喜欢就点点喜欢鼓励
DEMO路径:https://github.com/kingbuwu/poster
demo上封装了poster组件和显示头图图片自适应

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

推荐阅读更多精彩内容