云开发之图片压缩裁剪新姿势(CloudBase图像处理扩展实战)
发布于 4 年前 作者 weiliu 3365 次浏览 来自 分享

1、大约半年前在论坛里寻求方案无果,无奈退而求其次使用canvas做图片处理:

https://developers.weixin.qq.com/community/develop/doc/000c00a3d74758caca2a2b3ef5b400 (寻求方案发帖)

2、canvas做图片处理,代码量比较大,对手机性能要求比较高,而且如果一次处理图片多,还会偶现各种奇怪的不稳定问题。

3、最近iPhone微信更新到7.0.20更是直接不能使用了:

https://developers.weixin.qq.com/community/develop/doc/000cc4b48a4378003b7b2f97d51400 (bug反馈发帖)

4、更换图片处理的方案刻不容缓,上次云开发峰会上陈宇明大佬分享案例中提到一嘴CloudBase的相关支持,于是翻到了相关文章,一步步跟着操作,在此感谢大佬指路:

https://developers.weixin.qq.com/community/develop/article/doc/0004ec150708d0b57d5bd532a53413 (大佬文章)

https://cloud.tencent.com/document/product/876/42103 (开发指南)

5、本人电商项目中有多处图片处理需求,比较典型的一个业务是上传商品主图,当用户任意上传一个图片后,自动居中裁剪生成一大一小两张正方形的图,大的用在详情页,小的用在列表页。CloudBase支持两种方式:获取图片时处理、持久化图像处理。本人业务采用后者。

6、代码示例:

小程序端选择图片,上传到云存储

wx.chooseImage({
      count: 1,
      sizeType: ['compressed'],
      sourceType: ['album', 'camera'],
      success: res => {
        const tempFilePaths = res.tempFilePaths
        const tempFile = tempFilePaths[0]
        let pictureLarge = tempFile
        let fileName = pictureLarge.split('.')
        let format = fileName[fileName.length -1]
        let cloudPath = 'products/sellerId/original-' + (new Date()).valueOf() + (format.length < 5 ? '.' + format : '')
        wx.cloud.uploadFile({
          cloudPath: cloudPath,
          filePath: pictureLarge,
          success: res => {
            const pictureOrignial = res.fileID
            wx.cloud.callFunction({
              name: 'addProduct',
              data: {
                operation: 'addPicture',
                pictureOrignial,
                cloudPath
              }
            }).then(res => {
              if (res.result.errCode) {
                wx.showModal({
                  title: '主图处理失败',
                  content: res.result.errMsg,
                  showCancel: false,
                  confirmColor: '#67ACEB'
                })
              } else {
                //拿到云文件ID做后续处理 res.result.picture
              }
            }).catch(err => {
              console.error(err)
              wx.showModal({
                title: '主图处理失败',
                content: '主图处理失败,请重试',
                showCancel: false,
                confirmColor: '#67ACEB'
              })
            })

          },
          fail: err => {
            console.error(err)
            wx.showModal({
              title: '主图上传失败',
              content: '主图上传失败,请重试',
              showCancel: false,
              confirmColor: '#67ACEB'
            })
          }
        })
        
      }
    })

云函数端处理图片,先放大到最小边大于1125px,再分别裁剪出1125px和258px的两张图,存到同一目录下,返回云文件ID

// 云函数入口文件
const cloud = require('wx-server-sdk')
const extCi = require("[@cloudbase](/user/cloudbase)/extension-ci")
const tcb = require("tcb-admin-node")

cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
})

tcb.init({
  env: cloud.DYNAMIC_CURRENT_ENV
})
tcb.registerExtension(extCi)

// 云函数入口函数
exports.main = async (event) => {
  const wxContext = cloud.getWXContext()

  if (event.operation == 'addPicture') {

    return await addPicture(event.pictureOrignial, event.cloudPath)

  } else {
    
  }
  
}

async function addPicture(pictureOrignial, cloudPath) {

  //process picture
  const res = await process(cloudPath)
  if (res.errCode !== 0) {
    return {
      errCode: 100,
      errMsg: '商品主图处理失败'
    }
  } else {
    const pictureIDLarge = pictureOrignial.replace(/original/, 'large')
    const pictureID = pictureOrignial.replace(/original/, 'normal')
    return {
      errCode: 0,
      picture: {
        pictureIDLarge,
        pictureID
      }
    }
  }

}

async function process(cloudPath) {

  try {

    const opts = {
      //scale to 1125
      rules: [
        {
          fileid: '/' + cloudPath, // 处理结果的文件路径,如以’/’开头,则存入指定文件夹中,否则,存入原图文件存储的同目录
          rule: "imageMogr2/thumbnail/!1125x1125r" // 处理样式参数,与下载时处理图像在url拼接的参数一致
        }
      ]
    }

    await tcb.invokeExtension("CloudInfinite", {
      action: "ImageProcess",
      cloudPath: cloudPath, // 图像在云存储中的路径,与tcb.uploadFile中一致
      operations: opts
    })

  } catch (err) {
    return JSON.stringify(err, null, 4)
  }
  
  try {

    const opts = {
      rules: [
        //crop large
        {
          fileid: '/' + cloudPath.replace(/original/, 'large'),
          rule: "imageView2/1/w/1125/h/1125/q/85"
        },
        //crop normal
        {
          fileid: '/' + cloudPath.replace(/original/, 'normal'),
          rule: "imageView2/1/w/258/h/258/q/85"
        }
      ]
    }

    await tcb.invokeExtension("CloudInfinite", {
      action: "ImageProcess",
      cloudPath: cloudPath, // 图像在云存储中的路径,与tcb.uploadFile中一致
      operations: opts
    })

  } catch (err) {
    return JSON.stringify(err, null, 4)
  }

  return {
    "errCode": 0,
    "errMsg": "ok"
  }
}

回到顶部