微信小程序之分享海报生成

转自IMWeb社区,做者:结一,原文连接git

为了吸引更多的用户,设计好一个分享海报仍是颇有必要的。而小程序要生成一个海报仍是有点坑的,下面分享下咱们打卡小程序的一些经验。github

分享海报的效果图以下:web

制做要求:canvas

  • 海报以弹窗形式展示,各类手机型号均可以正常显示
  • 海报的内容由背景图、日期、随机的名言警句、活动的二维码及用户的参加活动的信息
  • 海报保存的图片大小为 iphone 6 的两倍图(750 * 1334)

因为看到的弹窗图片与保存的图片是两种大小,因此一开始看了些网上的其余教程,建议是搞两个 canvas 一个大的一个小的。实际过程当中,采用了一个大的 canvas ,让其偏离视窗显示区域(不可见)并生成临时文件,弹窗的图片再使用 img 组件,引入临时文件,设置其高度;而保存的时候则直接下载临时文件。小程序

虽然是实现了,可是后来在优化的过程当中,这个方案也从新设计了。下面具体介绍下优化过的方案:api

  • 优先使用一个 canvas 绘制二维码;
  • 弹窗的图片即为一个 canvas;
  • 分享的图片为该 canvas 导出的大图片;
  • 为了达到最佳效果,名言警句的换行录入时就处理好。

设计弹窗的图片比例

因为最后海报的图片大小为 iphone 6 的两倍图(750 * 1334),因此这里弹窗的图片也便是 canvas 的大小,设计为对应的尺寸的某个比例。bash

弹窗图片的高度 = 视窗的高度 - 上下留白 - 按钮的高度 - 图片与按钮的距离
imgHeight = 100vh - 40rpx * 2 - 50rpx - 15rpx

弹窗图片的宽度 /  弹窗图片的高度 = 750 / 1334
弹窗图片的宽度 = (750 / 1334) * 弹窗图片的高度
复制代码

因为像素只能是整数,因此这样绘制出来的图片可能底部会有1px的空白,因此在设置高度的时候能够再减掉 1px,这不会影响视觉效果。微信

绘制背景图

若是是网络图片,绘制背景图以前必定要先下载该图片,可经过 wx.getImageInfowx. downloadFile 下载图片,下载成功后将其塞进临时地址,而后使用 wx canvas 的 drawImage 绘制。注意若是地址是 base64 的话, gif 是不行的。网络

绘制二维码

绘制二维码换了好几个库,每一个在安卓下面生成的二维码都会频现失败。查了好些资料,说是安卓绘制的时候要设置个 setTimeout,因而最终选择了weapp-qrcode,修改了其绘制的函数,增长了setTimeout(还真别说,加上二维码绘制就成功了)。app

ctx.draw(false, function (e) {
	setTimeout(() => { // 修改增长的
    	options.callback && options.callback(e)
    }, 20);
})
复制代码

另:目前这些绘制小程序二维码的库都是在一个单独的新 canvas 中完成的,只要对源码稍做修改,就能够提供另外一个接口,直接在一个现有的 canvas (表示 canvas 中一开始绘制了其余内容) 中绘制。

若是二维码扫不出来,则表示二维码绘制出了问题。但安卓微信 6.7.2 版本自己有个 bug,二维码自己是没有问题,它却不能识别。不过升级下微信版本就行了。

保存图片

  • 先要获取用户是否开启用户受权相册
  • 若是没有权限,则弹窗提示开通权限,若是有权限直接调用 saveImageToPhotosAlbum 接口保存图片
  • 若是弹窗提示接受开通权限,则调用 saveImageToPhotosAlbum 接口保存图片
  • 若是弹窗提示拒绝则再次弹窗是否去设置开通权限,若是是则进入设置权限
// 先尝试保存
trySaveImg() {
  const _this = this;
  // 获取用户是否开启用户受权相册
  wx.getSetting({
    success(res) {
      // 若是没有则获取受权
      if (!res.authSetting['scope.writePhotosAlbum']) {
        wx.authorize({
          scope: 'scope.writePhotosAlbum',
          success() {
            _this.saveImg();
          },
          fail() {
          // 若是用户拒绝过或没有受权,则再次打开受权窗口
          // (ps:微信api又改了如今只能经过button才能打开受权设置,之前经过openSet就可打开,下面有打开受权的button弹窗代码)
            wx.showModal({
              title: '获取权限失败',
              content: '是否打开设置页,容许小程序保存图片到你的相册',
              success: () => {
                wx.openSetting({
                  success (sRes) {
                    if (sRes.authSetting['scope.writePhotosAlbum']) {
                      setTimeout(() => {
                        _this.saveImg();
                      }, 200);
                    }
                  },
                });
              },
            });
          },
        });
      } else {
        // 有则直接保存
        _this.saveImg();
      }
    },
  });
},
// 正式保存
saveImg() {
  const { tempImgPath } = this.data;

  wx.showLoading({
    title: '正在保存中...', // 提示的内容,
    mask: true, // 显示透明蒙层,防止触摸穿透,
  });

  wx.saveImageToPhotosAlbum({
    filePath: tempImgPath,
    success() {
      wx.showToast({
        title: '保存成功',
        icon: 'success',
        duration: 2000,
        mask: true,
      });
    },
    fail() {
      wx.showToast({
        title: '保存失败', 
        icon: 'none',
        duration: 2000,
        mask: true,
      });
    },
  });
},
复制代码

性能注意

经实践测试整个绘制过程其实仍是很快的,可是若是有保存临时文件操做( wx.canvasToTempFilePath ),那么这个操做通常得占一半时间左右。除此以外,有个 measureText api,用来测量文字的长度,这个在实现自动换行的时候用获得,可是比较耗性能。