图片 Buff 转 jpg

552 阅读1分钟

微信小程序从云函数获取到的二维码d Buffer, 生成图片从而生成海报。

  • 坑1:小程序对base64图片支持不友好,模拟器上图片可以显示,真机无法显示
  • 坑2:小程序canvas绘图必须使用网络图片或者本地图片,但是如果直接在wx.drawImage传入图片链接,真机上面会显示失败

解决思路:服务器生成二维码图片,微信小程序下载服务器图片。

微信小程序 cloud.openapi.wxacode.getUnlimited 返回给前端的 Buffer 类型是 ArrayBuffer, 转 Int8Array 类型传给后台, 后台 使用 fs.writeFileSync 生成图片

微信小程序代码

const bufferToImageURL = (buffer, fileName) => {
  return new Promise((resolve, reject) => {
    let arr = new Int8Array(buffer)
    let parameters = {
      arr: arr,
      fileName: fileName,
      byteLength: buffer.byteLength
    };
    wx.request({
      url: 'url', // 服务器生成图片的接口
      data: parameters,
      method: "POST",
      success(result) {
        if (result.statusCode === 200) {
          wx.downloadFile({
            url: 'url', // 服务器返回图片的地址
            success (res) {
              if (res.statusCode === 200) {
                resolve(res.tempFilePath)
              } else {
                reject(new Error("请求生成二维码成功, 下载二维码失败"));
              }
            }
          })
        } else {
          reject(new Error("请求生成二维码失败"));
        }
      },
      fail(err) {
        reject(new Error("请求生成二维码失败" + JSON.stringify(err)));
      }
    });
  })
}

服务器代码,使用 nodejs

// router
router.post('/qrCode/bufferToImage.fp', bufferToImage)
router.get('/download/wxImage/:fileName', downloadwxImage)

// controller
exports.downloadwxImage = async function (ctx, next) {
  try {
    var fileName = ctx.params.fileName;
    ctx.type = 'image/jpeg'; // 设置请求头类型
    let data = fs.readFileSync('public/tmp/' + fileName);
    ctx.body = data;
    fs.unlink('public/tmp/' + fileName); // 删除图片
  } catch (e) {
    ctx.body = false;
  }
}

exports.bufferToImage = async function (ctx, next) {
  try {
    var inputParams = ctx.request.body;
    let byteLength = inputParams.byteLength
    let data = [];
    for (let i = 0; i < byteLength; i++) {
      data.push(inputParams.arr[i]); // new Int8Array() 返回的是一个对象, 从中取出值
    }
    // 转 Buffer
    var buffer = Buffer.from(data);
    var fileName = inputParams.fileName;
    // 保存为图片格式
    fs.writeFileSync('public/tmp/' + fileName, buffer, 'binary')
    ctx.body = {
      fileName
    };
  } catch (e) {
    ctx.body = {
      success: false,
      message: e.message
    }
  }
};

参考

微信小程序 海报生成踩坑记