微信小程序中图片压缩的最佳实现与封装

时间:2024-10-05 07:40:02
  • const imgUtil = new (require('./imgUtil'))()
  • // 默认配置
  • const defaultConfig = {
  • restrictiveSize: 0.5 * 1024 * 1024, // 0.5MB
  • fixed: 1024,
  • quality: 0.3,
  • isOriginSize: false
  • }
  • // 是否支持
  • const isCanUseCompressImage = wx.canIUse('compressImage')
  • // 压缩耗时
  • let compressTime = Date.now()
  • let canvas = null
  • /**
  • * 压缩图片
  • * 支持类型:JPG
  • * @param {string} canvasId canvas的id
  • * @param {string} canvasWidthName 控制canvas宽度的变量名
  • * @param {string} canvasHeightName 控制canvas高度的变量名
  • *
  • */
  • function ImgCompress(canvasId, canvasWidthName, canvasHeightName) {
  • // 如果canvas上下文未创建,则创建canvas上下文
  • canvas = canvas || wx.createCanvasContext(canvasId)
  • // 压缩完成后销毁canvas
  • const destroyCanvas = function (newWidth, newHeight, fixed, that) {
  • canvas.clearRect(0, 0, newWidth, newHeight)
  • canvas = null
  • const width = fixed || defaultConfig.fixed
  • return that.setData({
  • [canvasWidthName]: width,
  • [canvasHeightName]: width * 9 / 16,
  • })
  • }
  • /**
  • * 压缩图片
  • * @param {string} filePath 图片的路径/临时路径
  • * @param {object} that 页面的this对象
  • * @param {int} quality 压缩质量(0-1,值越小压缩得越厉害)
  • * @param {bool} isOriginSize 是否保持原有宽高
  • * @param {int} fixed 修正宽度(最小宽度)
  • * @param {int} restrictiveSize 图片限制大小,单位:B
  • * @param {int} orderNumber 顺序序号
  • * @returns { Promise } errMsg: ok-成功 fail-失败, filePath: 压缩后路径, originPath: 原始路径, orderNumber: 序号
  • */
  • this.compressImage = async function (filePath, that, quality, isOriginSize, fixed, restrictiveSize, orderNumber) {
  • var limitSize = restrictiveSize || defaultConfig.restrictiveSize
  • const res = await imgUtil.getImgSize(filePath, orderNumber)
  • console.log('当前序号:', res.orderNumber);
  • console.log('原始大小(单位KB):', res.size * 1.0 / 1024)
  • // 超过限制则进行压缩
  • if (res.size > limitSize) {
  • const info = await imgUtil.getImgInfo(res.originalPath)
  • return new Promise((resolve, reject) => {
  • var cttSuccess = function (cres) {
  • compressTime = Date.now() - compressTime
  • console.log('压缩时长:', compressTime * 1.0 / 1000)
  • return resolve({
  • errMsg: 'ok',
  • filePath: cres.tempFilePath,
  • originPath: res.originalPath,
  • orderNumber: res.orderNumber
  • })
  • }
  • var cttFail = function (err) {
  • console.log('canvasToTempFilePath失败,图片路径:', res.originalPath)
  • console.log('canvasToTempFilePath失败:', err)
  • return resolve({
  • errMsg: 'fail',
  • filePath: '',
  • originPath: '',
  • orderNumber: res.orderNumber
  • })
  • }
  • // 如果支持原生压缩api并且图片的大小小于3MB则使用原生压缩
  • // 图片的大小在小于3MB时原生压缩api性能较好,耗时较少
  • if (isCanUseCompressImage && res.size <= 3 * 1024 * 1024) {
  • console.log('调用了CompressImage')
  • wx.compressImage({
  • src: info.path,
  • quality: (quality || defaultConfig.quality) * 100,
  • success: cttSuccess,
  • fail: cttFail
  • })
  • } else {
  • var newInfo = {
  • newW = info.width,
  • newH = info.height
  • }
  • // 不保持原有宽高,采用等比例缩放后的宽高
  • if(!isOriginSize){
  • newInfo = imgUtil.getUniformScaleInfo(info.width, info.height, quality || defaultConfig.quality, fixed || defaultConfig.fixed)
  • }
  • console.log('图片大小', {
  • original: { oriW: info.width, oriH: info.height },
  • newInfo: { newW: newInfo.newW, newH: newInfo.newH }
  • })
  • // 设置canvas的宽和高
  • that.setData({
  • [canvasWidthName]: newInfo.newW,
  • [canvasHeightName]: newInfo.newH
  • }, function () {
  • setTimeout(function () {
  • canvas.drawImage(info.path, 0, 0, newInfo.newW, newInfo.newH)
  • canvas.draw(false, function () {
  • // 保持原有宽高通过设置质量进行压缩,不保持原有宽高质量为1
  • wx.canvasToTempFilePath({
  • x: 0,
  • y: 0,
  • width: newInfo.newW,
  • height: newInfo.newH,
  • destWidth: newInfo.newW,
  • destHeight: newInfo.newH,
  • canvasId: canvasId,
  • fileType: 'jpg',
  • quality: isOriginSize ? quality || defaultConfig.quality : 1,
  • success: cttSuccess,
  • fail: function (err) {
  • // 失败后进行一次重试
  • wx.canvasToTempFilePath({
  • x: 0,
  • y: 0,
  • width: newInfo.newW,
  • height: newInfo.newH,
  • destWidth: newInfo.newW,
  • destHeight: newInfo.newH,
  • canvasId: canvasId,
  • fileType: 'jpg',
  • quality: isOriginSize ? quality || defaultConfig.quality : 1,
  • success: cttSuccess,
  • fail: cttFail,
  • complete: function () {
  • destroyCanvas(newInfo.newW, newInfo.newH, fixed, that)
  • }
  • })
  • },
  • complete: function () {
  • destroyCanvas(newInfo.newW, newInfo.newH, fixed, that)
  • }
  • })
  • })
  • }, 30)
  • })
  • }
  • })
  • } else {
  • return {
  • errMsg: 'ok',
  • filePath: res.originalPath,
  • originPath: res.originalPath,
  • orderNumber: res.orderNumber
  • }
  • }
  • }
  • /**
  • * 删除压缩过程中保存的图片
  • * @param {string} tempFilePath 保存的图片的路径
  • */
  • this.removeSavedFile = function (tempFilePath) {
  • wx.removeSavedFile({
  • filePath: tempFilePath,
  • success: function () {
  • console.log('删除保存的图片\n\r')
  • },
  • fail: function (err) {
  • console.log('删除保存的图片失败:' + err.errMsg + '\n\r')
  • }
  • })
  • }
  • }
  • // 组合使用构造函数模式与原型模式
  • ImgCompress.prototype = {
  • constructor: ImgCompress
  • }
  • module.exports = ImgCompress