Skip to content

在小程序中生成海报

  1. wxml中定义供生成海报的画布:
html
<canvas
  style="width: 375px;height: 375px;position:fixed;top:-2000px;opacity: 0;"
  type="2d"
  id="canvas"
  canvas-id="canvas"
/>
  1. 配置通用canvas函数
js
// 画布相关操作

// 获取一个可填充到画布的图片元素
export const loadCanvasImage = function (canvas, path) {
    return new Promise((resolve) => {
        const image = canvas.createImage()
        image.src = path
        image.onload = () => {
            resolve(image)
        }
    })
}

// 将画布转换为文件路径,微信画布使用canvasId,其余用canvas
export const canvasToFilePath = function (options,context) {
    return new Promise((resolve) => {
        wx.canvasToTempFilePath({
            ...options,
            success: (res) => {
                resolve(res.tempFilePath)
            }
        },context)
    })
}

// 重新设置画布大小,否则画布中的图片将会变形,生成海报专用
export const formatCanvasSize = function (element, ctx) {
    return new Promise((resolve) => {
        wx.getSystemInfo({
            success: (result) => {
                const pxRatio = result.pixelRatio
                const canvas = element.node
                canvas.width = element.width * pxRatio
                canvas.height = element.height * pxRatio
                ctx.scale(pxRatio, pxRatio)
                resolve()
            }
        })
    })
}

// 根据画布选择器选择画布,2d画布专用,canvas元素上需标识 type=2d
export const getCanvas = function (selector,component,fileds = {
    node: true,
    size: true,
    rect: true
}) {
    return new Promise((resolve, reject) => {
        wx.createSelectorQuery().in(component).select(selector).fields(fileds).exec((res) => {
            resolve(res[0])
        })
    })
}
  1. 生成海报
js
Component({
  options: {
    styleIsolation: 'shared',
  },
  methods: {
    // 绘制内容
    async drawPoster(canvas, ctx, groupInfo) {

      // 背景
      ctx.fillStyle = "#fff";
      ctx.fillRect(0, 0, 375, 375);

      // 插入图片
      const {
        pixelRatio
      } = wx.getSystemInfoSync()
      const qrCodeTempFilePath = await canvasToFilePath({
        canvasId: 'group-code',
        destWidth: rpx2px(400) * pixelRatio,
        destHeight: rpx2px(400) * pixelRatio,
        fail:(err)=>{
          console.log(err)
        }
      },this)

      const image = await loadCanvasImage(canvas, qrCodeTempFilePath)
      ctx.drawImage(image, 88, 50, 200, 200)

      // 文案
      ctx.fillStyle = '#333333';
      ctx.font = "18px '微软雅黑'";
      ctx.textAlign = 'center'
      // ctx.fillText(`集体码:${createCode(groupInfo)}`, 188, 280, 375)
      ctx.fillText(groupInfo.name, 188, 300, 375)
    },
    toSavePoster() {
      this.setData({
        onExport: true,
      });
      wx.showLoading({
        title: '正在生成海报...',
      });
      try {
        // 获取将要用于生成海报的元素
        const exportCanvasElement = await getCanvas('#canvas', this);
        const exportCanvas = exportCanvasElement.node
        const exportCanvasCtx = exportCanvas.getContext('2d')

        // 重新设置画布大小,否则画布中的图片将会变形
        formatCanvasSize(exportCanvasElement, exportCanvasCtx)

        // 绘制海报内容
        await this.drawPoster(exportCanvas, exportCanvasCtx, this.data.code)

        // 生成海报地址
        const posterPath = await canvasToFilePath({
          canvas: exportCanvas
        })
        // 放置在 toast 之前避免 toast 也一起被清除
        wx.hideLoading({
          success: (res) => { },
        })
        // 保存到本机
        wx.saveImageToPhotosAlbum({
          filePath: posterPath,
          success: () => {
              wx.showToast({
                title: '集体码已保存到相册',
              })
            }
        })
      } catch (err) {
        console.log(err);

        // 放置在 toast 之前避免 toast 也一起被清除
        wx.hideLoading({
          success: (res) => {},
        });
        wx.showToast({
          title: '生成失败,请稍后重试',
          icon: 'none',
        });
      }
      this.setData({
        onExport: false,
      });
    }
  }
});