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"
}
}