小程序导出朋友圈海报详细记录

小程序提供了转发给好友的接口,但是没提供分享到朋友圈的接口。于是,只有引导用户保存图片分享到朋友圈。
两种方案:用微信 api 手动保存,用 painter

微信 api

使用原生接口的话,大致是使用 canvas 绘制出海报,然后下载。所以重点是绘制出海报,下载的流程都是一样的。当然在保存图片到相册前,还会需要获取保存图片到相册的权限。总结下来就是canvas绘制,获取保存权限,保存图片这三个步骤。
首先来看绘制海报,需要使用以下接口

  • wx.createCanvasContext 创建 canvas context
  • ctx.drawImage 绘制图片到 canvas
  • ctx.fillText 写文字
  • wx.getImageInfo 获取网络图片的 tempFilePath
  • ctx.draw canvas 绘制

最终保存下来的海报是这样的


wx816dc6e826dcc6b5.o6zAJs298QQbQgcF7A5dTg_F9y2s.S7bTLz7u0Rbr691154e07805442dba9bccedfcf52c3d.png

绘制的内容很简单,首先就是背景图;然后是分享者的头像;接下来是 @ xx 邀请你 这样一个文本描述;最后就是底部的小程序码。

首先,创建 canvas 画布

        <canvas canvas-id='canvas' class='canvas' :style="{height: windowHeight + 'px'}"/>

使用小程序 createCanvasContext api,需要传入 canvasid

        const ctx = wx.createCanvasContext('canvas')

然后将背景图片绘制出来,背景图片是放在本地的图片。

ctx.drawImage('../../../static/assets/img/poster_background.png', 0, 0, this.windowWidth, this.windowHeight)

然后写上文字

ctx.setFontSize(12);
ctx.setFillStyle('#FFFFFF');
ctx.setTextAlign('center');
ctx.fillText(`${this.privateUserInfo.nickname} 邀您领取`, this.windowWidth / 2, this.transformScale(520))

这里会将原始尺寸和绘制的尺寸等比例转换一下,就不赘述了。再接下来就是绘制小程序码了。由于小程序码是带了分享者的信息,所以必须是临时获取的网络图片资源,具体怎么获取带有分享者信息的小程序码,会专门写一篇文章介绍。

绘制图片

绘制头像与小程序码,这两张图片都是网络资源,所以都要使用 wx. getImageInfo 接口将其下载下来放到微信内存中,然后使用其response.path 绘制。小程序并不支持直接的绘制网络图片,而且也不支持 base64图片的绘制(虽然模拟器上会有效果)。头像的绘制还有有一个裁剪圆形头像的过程。wx.getImageInfo是异步的,所以在回调函数里绘制,当然这不是好的方式。可以使用 promise 来解决,由于现在已经不用这个代码了,就没有去改了。

wx.getImageInfo({
          src: miniProgramCodeSrc,
          success: (response) => {
            const miniProgramCodeSize = this.transformScale(160)
            ctx.drawImage(response.path, this.transformScale(85), this.transformScale(710), miniProgramCodeSize, miniProgramCodeSize)

            wx.getImageInfo({
              src: this.privateUserInfo.avatar,
              success: (response) => {
                const avatarSize = this.transformScale(100)
                //先绘制圆,裁剪成圆形图片
                ctx.save();
                ctx.beginPath();
                //圆的原点x坐标,y坐标,半径,起始弧度,终止弧度
                ctx.arc(this.transformScale(320), this.transformScale(425), avatarSize / 2, 0, 2 * Math.PI);
                ctx.setStrokeStyle('#ffffff');
                ctx.stroke();
                ctx.clip();

                ctx.drawImage(response.path, this.transformScale(270), this.transformScale(375), avatarSize, avatarSize)
                ctx.restore();

                ctx.draw(false, () => {
                  this.saveToTempFilePath()
                })
              }
            })
          }
        })

到这一步,绘制基本就结束了。我们所要的海报内容已经可以在 canvas 上呈现了,接下来就是将 canvas 的内容保存为图片了。值得提醒的是,ctx.draw这个接口也是异步的,需要在其回调中执行下载的操作。

获取 tempFilePath

  • wx.canvasToTempFilePath 获取整个 canvas 的tempFilePath

保存图片最重要的就是tempFilePath了,使用canvasToTempFilePath 获取 tempFilePath。需要注意的是canvasToTempFilePath接口二参需要传入 this。

      saveToTempFilePath() {
        wx.canvasToTempFilePath({
          canvasId: 'canvas',
          success: (response) => {
            //获取相册授权
          }
        }, this)
      }

获取 tempFilePath 成功后再获取保存权限,当然也可以先获取保存权限,再获取tempFilePath。

获取保存权限

首先查看是否有保存权限,有权限就可以直接保存了。没有权限就先获取权限,再保存。

  • wx.getSetting 查看权限列表
  • wx.authorize 若没有保存图片权限,进行授权
wx.getSetting({
  success: (res) => {
    if (!res.authSetting['scope.writePhotosAlbum']) {
      wx.authorize({
        scope:'scope.writePhotosAlbum',
        success: () => {
          this.saveImageToPhotosAlbumByWX(response.tempFilePath)
        }
      })
    } else {
      this.saveImageToPhotosAlbumByWX(response.tempFilePath)
    }
  }
})

保存图片到相册

  • wx.saveImageToPhotosAlbum 保存图片到相册

这一步就很简单了,万事俱备,只差保存了。调用 wx.saveImageToPhotosAlbum 即可。

      saveImageToPhotosAlbumByWX(tempFilePath) {
        wx.saveImageToPhotosAlbum({
          filePath: tempFilePath,
          complete: () => {
            // 其他操作
          }
        })
      }

到这里,使用原生 api 保存一张分享朋友圈的海报就好了。

painter

painter 是什么呢?

小程序生成图片库,轻松通过 json 方式绘制一张可以发到朋友圈的图片

painter 是酷家乐开源的小程序图片生成库,类似 echarts,使用配置对象渲染图片到 canvas。渲染完成后回调会返回 tempFilePath,然后调用 wx.saveImageToPhotosAlbum 即可保存。保存的步骤和第一种方案一致,关键是获取到 tempFilePath。

按照其 readme 来操作就好了,由于项目是使用了 mpvue,所以使用了mpvue接入方案

使用 painter

        <painter v-if="showPainter" class='canvas' @imgOK="onImgOk" :palette="palette"/>

为什么要使用 v-if 呢,需要在所有数据都准备好了后再渲染 painter,否则会无限绘制。

data() {
  return {
    //painter 配置数据
    palette: {
      width: '640rpx',
      height: '1008rpx',
      background: '/static/assets/img/poster_background.png',
      views: [
        {
          type: 'image',
          url: '',
          css: {
            top: '380rpx',
            left: '320rpx',
            align: 'center',
            width: '100rpx',
            height: '100rpx',
            borderRadius: '50rpx'
          }
        }, {
          type: 'text',
          text: '',
          css: {
            top: '490rpx',
            left: '320rpx',
            align: 'center',
            fontSize: '24rpx',
            color: '#fff'
          }
        },
        {
          type: 'image',
          url: '',
          css: {
            top: '690rpx',
            left: '85rpx',
            width: '180rpx',
            height: '180rpx'
          }
        }
      ]
    }

  }
},

computed: {
  showPainter() {
    const avatar = this.palette.views[0].url
    const text = this.palette.views[1].text
    const qrCodeUrl = this.palette.views[2].url
    return avatar !== '' && text !== '' && qrCodeUrl!== ''
  }
}

在 painter绘制成功的回调里,将 tempFilePath 保存起来。接下来的权限获取和保存图片到相册流程就和上一个方案一致了。但是,需要提醒的是,tempFilePath 需要放在全局变量中,不能放在data 中。

总结

总结一下,遇到的一些坑

  • 小程序canvas不能支持 base64
  • drow 有回调
  • drawImage 不能直接使用网络图片
  • 需要处理获取权限,用户拒绝后的场景

最后

海报就暴露了,是的,就是漫游鲸。欢迎扫个码体验漫游鲸小程序,欢迎了解下漫游鲸。如果还不了解漫游鲸,那么点击就能了解漫游鲸啦

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

推荐阅读更多精彩内容

  • 转载链接 注:本文转载知乎上的回答 作者:初雪 链接:https://www.zhihu.com/question...
    pengshuangta阅读 28,475评论 9 295
  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 12,682评论 2 59
  • 曾经的经典路线从岩子南,上五条梁,再到摩天岭,已经被紫金山景区圈到了景区里面。要走这条路线需要买门票进景区,仅这一...
    阿果悠悠阅读 407评论 0 0
  • 一、新股申购 今日无新股申购与转债申购 二、全球股市 机构最新净买入金额排行 (根据当日机构席位净买入金额排名) ...
    db1eae6e5a78阅读 463评论 0 0
  • 一、“你不是说要开始写手帐吗?怎么没看到你有所行动呀?”“哎呀,我买的工具还没有到。我今天还催客服了,说什么大雪要...
    happycat悦大喵阅读 364评论 1 1