小程序图片上传压缩

这篇具有很好参考价值的文章主要介绍了小程序图片上传压缩。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

上传图片是小程序常见的功能,例如点评类小程序邀请用户分享照片、电商类小程序要求商家上传商品照片。

伴随着照片像素越来越高,图片体积越来越大,小程序开发者需要压缩图片,否则将导致用户上传图片失败或加载时间过长等影响体验的情况。

小程序提供 wx.chooseMedia、wx.canvasToTempFilePath、wx.compressImage 3 个图片类接口,便于开发者在不同应用场景下处理图片。除此以外,这 3 个接口的巧妙结合能够满足更多元化的图片压缩需求。下面就来看看怎样使用吧!

wx.chooseMedia

wx.chooseMedia 支持在使用小程序过程中拍摄或从手机相册选择图片或视频,其 sizeType 属性支持是否上传缩略图。该接口应用简便,接入即可实现压缩图片效果,省时省力。

wx.chooseMedia({
  count: 9,
  mediaType: ['image'], // 只允许选择图片
  sourceType: ['album', 'camera'],  // 可以拍摄或从相册中选择
  sizeType:['compressed'],  // 选择压缩图
  camera: 'back', // 后置摄像头
  success(res) {
    console.log(res)
  }
});

然而,该接口在压缩图片方面也有一定的限制:

  • 无法指定压缩质量

  • 部分安卓机型存在压缩失效的情况

  • iOS 和安卓的压缩机制不同,需要进行合理兼容

wx.canvasToTempFilePath

开发者可以通过控制 Canvas.createImage 绘制图片到 Canvas,然后利用 wx.canvasToTempFilePath 接口转换成图片。

这种方法能够高效控制图片宽高尺寸以及压缩质量,非常适用于有图片要求的场景。

wx.canvasToTempFilePath({
  width: 50, // 画布区域的宽度
  height: 50,  // 画布区域的高度
  destWidth: 100,  // 输出图片的宽度
  destHeight: 100,  // 输出图片的高度
  canvasId: 'myCanvas',
  quality: 1,  // 图片质量0-1
  success(res) {
    console.log(res.tempFilePath)
  }
});

但是这种方式也会存在一定的限制:

  • iOS 和安卓的压缩机制不同,需要进行合理兼容

  • 通过 Canvas 转换的图片存在略微色差

wx.compressImage

开发者可以调用wx.compressImage 接口直接压缩图片,而且支持选择压缩质量,不限制图片宽高尺寸,非常适用于处理特殊大小的图片。

wx.compressImage({
  src: '', // 图片路径
  quality: 80 // 压缩质量 0-100
});

同时这种方式也需要考虑不同系统的压缩差异:

  • 在压缩到极限值时,iOS 压缩图画质不会随着压缩质量变小而变化

  • 在压缩质量小于 1 时,安卓系统输出的画质将不再变小

多方式结合处理

回顾常见的小程序业务场景,图片处理主要聚焦于用户上传图片、列表展示这 2 个环节,可以结合以上 3 个接口实现最佳图片处理方式,既能够利用接口自带的压缩功能,省时省力;又能够解决图片太大造成的压缩难题。

  1. 判断系统类型

判断当前系统是 iOS 系统还是安卓系统

function isIOS(){
	return wx.getSystemInfo().then(res => {
		return /IOS/ig.test(res.system);
	});
}
  1. 根据系统选择上传方式

iOS 系统:设置 sizeType 为 [‘compressed’],利用 iOS 压缩体系自动压缩

安卓系统:设置 sizeType 为 [‘original’, ‘compressed’],让用户自主选择上传原图或压缩图。

这种方式一方面利用接口自带的压缩能力; 另一方面如果图片宽高大于安卓能清晰压缩的值(例如40000),用户会预览到比较模糊的照片而选择上传原图

  1. 验证大小,手动压缩

当用户选择图片后,wx.chooseMedia 返回的 tempFiles 显示对应图片的大小。如果该图片大小大于限制值,则进行手动压缩。

  1. 根据宽高选择压缩方式

通过 wx.getImageInfo 获取图片的宽高:

如果宽度或高度大于 4096,调用 wx.compressImage 强制压缩

如果宽度和高度都小于 4096,绘制 Canvas 实现压缩,设置压缩基础宽高为 1280

代码如下:

// compressImage.js
/**
 * @param {object} img 包含path:图片的path,size:图片的大小
 * @param {object} canvas canvas对象
 * @param {number} fileLimit 文件大小限制
 * @returns {Promise} 返回Promise对象
 */
function _compressImage(img, canvas, fileLimit) {
  return wx.getSystemInfo().then(res => {
    let {
      // 设备像素比
      pixelRatio,
      // 设备品牌
      system
    } = res;
    // 是否是IOS系统
    let isIOS = /(ios)/ig.test(system);
    // 文件限制
    fileLimit = fileLimit || 2 * 1024 * 1024;
    // 基础大小
    let baseSize = 1280;
    // 大于文件限制,手动压缩
    if (img.size > fileLimit) {
      return compressImg({src:img.path, size:img.size, canvas, baseSize, isIOS, pixelRatio}).then(response => {
        return Promise.resolve(response);
      });
    }
    return Promise.resolve(img.path);
  });
}

/**
 * @description 根据图片的大小选择压缩的方式
 * @param {string} src 图片的path
 * @param {number} size 图片的大小
 * @param {object} canvas canvas对象
 * @param {number} baseSize 基础尺寸
 * @param {boolean} isIOS 是否是IOS系统 
 * @returns {Promise} 返回Promise对象
 */
function compressImg({src, size, canvas, baseSize, isIOS, pixelRatio}) {
  return new Promise((resolve, reject) => {
    wx.getImageInfo({
      src
    }).then(res => {
      let imgWidth = res.width;
      let imgHeight = res.height;
      if (imgWidth <= 4096 && imgHeight <= 4096) {
        // 小于4096使用canvas压缩
        canvasToImage({src, size, imgWidth, imgHeight, canvas, baseSize, isIOS, pixelRatio}).then(response => {
          resolve(response);
        });
      } else {
        // 超过4096使用强制压缩
        compressImage(src, size, isIOS).then(response => {
          resolve(response);
        });
      }
    }).catch(err => {
      // 使用强制压缩
      compressImage(src, size, isIOS).then(response => {
        resolve(response);
      });
    });
  });
}

/**
 * @description 使用wx.compressImage压缩图片
 * @param {string} src 图片的path
 * @param {number} size 图片的大小
 * @param {boolean} isIOS 是否是IOS系统
 * @returns {Promise} 返回Promise对象
 */
function compressImage(src, size, isIOS) {
  return new Promise((resolve, reject) => {
    let quality = 100;
    if (isIOS) {
      quality = 0.1;
    } else {
      let temp = 30 - (size / 1024 / 1024);
      quality = temp < 10 ? 10 : temp;
    }
    wx.compressImage({
      src,
      quality,
      success: (res) => {
        resolve(res.tempFilePath);
      },
      fail: () => {
        // 压缩失败返回传递的图片src
        resolve(src);
      }
    });
  });
}

/**
 * @description 使用canvans压缩图片
 * @param {string} src 图片的path
 * @param {number} size 图片的大小
 * @param {number} imgWidth 图片的宽度
 * @param {number} imgHeight 图片的高度
 * @param {object} canvas canvas对象
 * @param {number} baseSize 基础尺寸
 * @param {boolean} isIOS 是否是IOS系统
 * @param {number} pixelRatio 设备像素比
 * @returns {Promise} 返回Promise对象
 */
function canvasToImage({src, size, imgWidth, imgHeight, canvas, baseSize, isIOS, pixelRatio}) {
  return new Promise((resolve, reject) => {
    if (!canvas) {
      compressImage(src, size).then(res => {
        resolve(res);
      });
      return;
    }
    // 设置canvas宽度和高度
    let canvasWidth = 0;
    let canvasHeight = 0;
    let quality = 1;
    // 图片的宽度和高度都小于baseSize,宽高不变
    if (imgWidth <= baseSize && imgHeight <= baseSize) {
      canvasWidth = imgWidth;
      canvasHeight = imgHeight;
      quality = 0.3;
    } else {
      let compareFlag = true;
      // 图片的一边大于baseSize,宽高不变
      if (pixelRatio > 2 && (imgWidth > baseSize || imgHeight > baseSize) && (imgWidth < baseSize || imgHeight < baseSize)) {
        canvasWidth = imgWidth;
        canvasHeight = imgHeight;
        quality = 0.3;
      } else {
        // 按照原图的宽高比压缩
        compareFlag = pixelRatio > 2 ? (imgWidth > imgHeight) : (imgWidth > imgHeight);
        // 宽比高大,宽按基准比例缩放,高设置为基准值,高比宽大,高按基准比例缩放,宽设置为基准值。
        canvasWidth = compareFlag ? parseInt(imgWidth / (imgHeight / baseSize)) : baseSize;
        canvasHeight = compareFlag ? baseSize : parseInt(imgHeight / (imgwidth / baseSize));
        quality = 0.9;
      }
    }
    let pic = canvas.createImage();
    pic.src = src;
    pic.onerror = function () {
      // 加载失败使用强制压缩
      compressImage(src, size, isIOS).then(response => {
        resolve(response);
      });
    }
    pic.onload = function () {
      // 获取绘画上下文
      let ctx = canvas.getContext('2d');
      ctx.clearRect(0, 0, canvasWidth, canvasHeight);
      ctx.drawImage(pic, 0, 0, canvasWidth, canvasHeight);
      // 导出图片
      wx.canvasToTempFilePath({
        canvas,
        width: canvasWidth,
        height: canvasHeight,
        destHeight: canvasHeight,
        destWidth: canvasWidth,
        fileType:'jpg',
        quality,
        success: (res) => {
          resolve(res.tempFilePath);
        },
        fail: (err) => {
          // 压缩失败使用强制压缩
          compressImage(src, size, isIOS).then(response => {
            resolve(response);
          });
        }
      });
    }
  });
}

/**
 * @description 循环压缩图片
 * @param {object} img 包含path:图片的path,size:图片的大小
 * @param {object} canvas canvas对象
 * @param {number} fileLimit 文件大小限制
 * @returns {Promise} 返回Promise对象
 */
async function cycleCompressImg(img, canvas, fileLimit) {
  let fileSystemManager = wx.getFileSystemManager();

  function getFileInfoPromise(src) {
    return new Promise((resolve, reject) => {
      fileSystemManager.getFileInfo({
        filePath: src,
        success: (res) => {
          resolve(res);
        },
        fail: (err) => {
          reject(err);
        }
      });
    });
  }
  let size = await getFileInfoPromise(img.path).size;
  let path = img.path;
  while (size > fileLimit) {
    path = await _compressImage(img, canvas, fileLimit);
  }
  return path;
}

module.exports = {
  _compressImage,
  cycleCompressImg
};

使用

在需要使用的页面中,引入上面的代码。
由于在压缩中使用canvas因此需要在wxml文件中添加canvas元素

<view class="upload">
  <view class="imageList">
    <block wx:if="{{uploadedFilePaths && uploadedFilePaths.length}}">
      <view class="imageList_item" wx:for="{{uploadedFilePaths}}" wx:key="index">
        <image src="{{item}}" class="upload_file"></image>
        <view class="close" bindtap="handleClose" data-index="{{index}}">
          <text class="flow">x</text>
        </view>
      </view>
    </block>
    <view wx:if="{{uploadedFilePaths.length < maxCount}}" class="camera" bindtap="handleCameraTap">
      <canvas type="2d" id="uploadCanvas" class="canvas"></canvas>
    </view>
  </view>
</view>

样式

/* components/upload/index.wxss */
.upload{
  margin-top:20rpx;
}
.camera {
  width: 100rpx;
  height: 100rpx;
  border: 1px solid #d9d9d9;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 12rpx;
  background-color: #fff;
  position: relative;
}

.imageList {
  display: flex;
  align-items: center;
}

.imageList_item {
  border-radius: 12rpx;
  position: relative;
  width: 100rpx;
  height: 100rpx;
  margin-right: 20rpx;

}

.close {
  width: 32rpx;
  height: 32rpx;
  background-color: rgba(90, 90, 90, 0.3);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  position: absolute;
  right: 0;
  top: 0;
  font-size: 24rpx;
  color: #fff;
}

.flow {
  display: flow-root;
  height: 100%;
  line-height: 100%;
}

.canvas {
  width: 100rpx;
  height: 100rpx;
  opacity: 0;
  position: absolute;
  z-index: -1;
  display: none;
}

.upload_img{
  width: 48rpx;
  height: 48rpx;
  border-radius:12rpx;
}
.upload_file{
  width: 100rpx;
  height: 100rpx;
  border-radius: 12rpx;
}

然后在js文件中,调用选择图片的api,由于版本的更迭使用的api也在变化,因此为了能够方便使用把微信小程序中目前常用的选择图片的api封装成一个函数,代码如下:

// chooseImage.js
/**
 * @description 选择图片
 * @param {object} options 选择图片的参数对象
 * @returns {Promise} 返回Promise对象
 */
function chooseImage(options) {
  options = options || {};
  return wx.getSystemInfo().then(res => {
    let {
      system
    } = res;
    let isIOS = /ios/gi.test(system);
    let sizeType = isIOS ? ['compressed'] : ['origin', 'compressed'];
    if (wx.canIUse('chooseImage')) {
      return new Promise((resolve, reject) => {
        wx.chooseImage({
          count: options.count || 9,
          sizeType: options.sizeType || sizeType,
          sourceType: options.sourceType || ['album', 'camera'],
          success: (res) => {
            resolve(res);
          },
          fail: (err) => {
            reject(err);
          }
        });
      });
    } else if (wx.canIUse('chooseMedia')) {
      return new Promise((resolve, reject) => {
        wx.chooseMedia({
          count: options.count || 9,
          mediaType: ['image'],
          sourceType: options.sourceType || ['album', 'camera'],
          success: (res) => {
            res.tempFiles = res.tempFiles.map(item => {
              item.path = item.tempFilePath;
              return item;
            });
            resolve(res);
          },
          fail: (err) => {
            reject(err);
          }
        });
      });
    }
  });
}

module.exports = chooseImage;

引入上面的compressImage.jschooseImage.js的 代码

const chooseImage = require('./chooseImage');
const {
_compressImage
} = require('./compressImage');
Page({
data:{
// 保存上传的文件路径
	uploadFilePaths:[],
	// 上传的最大文件数量
	maxCount:5,
	// 文件大小限制,单位kb,超过限制压缩文件
	limitSize:1024
},
// 上传图片
uploadImg() {
      wx.getSetting().then(res => {});
      if (this.data.uploadedFilePaths.length < this.data.maxCount) {
        const appAuthorizeSetting = wx.getSystemInfoSync(),
        cameraAuthorized = appAuthorizeSetting.cameraAuthorized,
        albumAuthorized = appAuthorizeSetting.albumAuthorized;
        // 相册或相机没有授权,先设置权限
        if ((albumAuthorized !== undefined && !albumAuthorized) || !cameraAuthorized) {
         wx.openAppAuthorizeSetting().then(auth => {}).catch(e => {});
        } else {
          let {
            maxCount
          } = this.data;
          // 授权后选择图片
          chooseImage({
            count: maxCount
          }).then(res => {
            let {
              tempFiles,
            } = res;
            if (tempFiles.length <= maxCount) {
              if ((tempFiles.length + this.data.uploadedFilePaths.length) > maxCount) {
                showToast({
                  title: '最多上传' + maxCount + '张图片'
                });
                return ;
              }
            } else {
              showToast({
                title: '最多上传' + maxCount + '张图片'
              });
              return ;
            }
            this.getCanvas('uploadCanvas').then(canvas => {
              if (canvas) {
                let proArr = tempFiles.map(item => {
                  return compressImage._compressImage(item, canvas, this.data.limitSize);
                });
                Promise.all(proArr).then(res => {
                  this.data.uploadedFilePaths = this.data.uploadedFilePaths.concat(res);
                  this.setData({
                    uploadedFilePaths: this.data.uploadedFilePaths
                  });
                  this.triggerEvent('upload', {
                    value: this.data.uploadedFilePaths
                  });
                });
              }
            });
          }).catch(err => {});
        }
      }
    },
    // 获取canvas,用于压缩图片
    getCanvas(id) {
      return new Promise((resolve, reject) => {
        let query = wx.createSelectorQuery();
        query.in(this);
        query.select(`#${id}`).fields({
          node: true,
          size: true
        }).exec((res) => {
          if (res[0]) {
            resolve(res[0].node);
          } else {
            resolve(null);
          }
        });
      });
    },
})

每种图片处理方式都有其突出的优势,结合多种方式能够最优地解决问题,适用于目标场景,便利用户上传图片的体验。文章来源地址https://www.toymoban.com/news/detail-499767.html

到了这里,关于小程序图片上传压缩的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • uni-app开发微信小程序,H5 关于压缩上传图片的问题

    文章目录 前言 一、为什么要压缩图片 二、图片压缩方式 1. 微信小程序​​​​​​​ 2. H5 总结 关于微信小程序、H5兼容性问题,今天就压缩以及上传图片做一个可实现方法的简要阐述。 在使用uni-app开发小程序及H5的具体业务中,我们会遇到需要让用户上传本地图片的场景

    2024年02月02日
    浏览(70)
  • 微信小程序wx.canvasToTempFilePath压缩上传图片,ios压缩成功但是数据sm2加密后无法发起请求,安卓一切正常

    吐槽遇到的问题~ 在写微信小程序的时候,采用wx.canvasToTempFilePath压缩图片且上传的时候,安卓一切正常,我在开发工具上也一切正常,偏偏ios上就不正常,不正常不是指压缩失败,而是明明也压缩成功了,竟然发不起网络请求,离大谱。因为所有请求的入参都会经过sm2加密,

    2024年02月08日
    浏览(55)
  • uniapp 上传图片时压缩图片

    提示:这里简述项目相关背景: 最近用uniapp做一个上传图片,要把图片大小压缩到200kb,然后传给后端 image-conversion:一个简单易用的JS图像转换工具,可以指定大小以压缩图像 npm i image-conversion --save const imageConversion = require(“@/components/image-conversion”);

    2024年02月12日
    浏览(38)
  • 前端Vue图片上传组件支持单个文件多个文件上传 自定义上传数量 预览删除图片 图片压缩

    前端Vue图片上传组件支持单个文件多个文件上传 自定义上传数量 预览删除图片 图片压缩, 下载完整代码请访问uni-app插件市场址:https://ext.dcloud.net.cn/plugin?id=13099 效果图如下: 组件初始化 使用方法 HTML代码部分

    2024年02月09日
    浏览(75)
  • Vue前端压缩图片后上传,拍照上传最佳实践

    最近有一个需求,通过手机拍照后上传图片到服务器,大家应该都知道,现在的手机像素实在是太高了,随便拍一张都是 10M 以上,直接上传到服务器一方面是浪费存储空间,另外就是特别浪费流量,如果网络不好还很慢。所以想寻求一种前端压缩图片的方案。 在网上找了很

    2024年02月10日
    浏览(65)
  • Element-ui 上传图片前压缩图片

    上传前把图片大小进行一个压缩在进行上传。 文章目录 需求:项目当中上传图片的需求点肯定有很多,再上传之后,如果图片很大的话,在加载的时候就会很慢。最近发现系统首次加载越来越慢,就开始思考怎么能降低这个加载时间,由于首页图片很多,所以图片的大小就

    2024年02月06日
    浏览(57)
  • FastAdmin上传图片服务端压缩图片,实测13.45M压缩为29.91K

    先前条件:第一步安装compose,已安装忽略。 先上截图看效果 一、在fastadmin的根目录里面输入命令安装think-image 二、找到公共上传类,application/common/library/Upload.php,在最下面新添加一个压缩方法 三、在application/common/library/Upload.php文件中,找到里面的 upload() 方法,在文件上传

    2024年01月18日
    浏览(51)
  • vue2上传图片image-conversion压缩

    项目中涉及上传图片,如果大体积的一般都需要压缩,这里我使用image-conversion来压缩 其实在npm中使用已经说得很明白了,我这里记录一下跟element ui上传组件配合使用 1、安装image-conversion 2、引入使用 2.1、这里配合element ui的上传组件配合使用 上传前方法中处理压缩逻辑,压

    2024年01月21日
    浏览(41)
  • 【vue3】前端上传图片的格式大小限制和压缩

    目录 前言 对上传图片进行格式大小限制 压缩上传图片 上篇文章中研究了如何使用双token机制,在此篇中就暴露了一些问题:当accesstoken过期后,直到拿到最终想要得到的数据,期间需要经历三次请求——第一次请求,拿到accesstoken过期的消息——第二次携带refreshtoken发起请求

    2024年02月06日
    浏览(75)
  • thinkphp5实现ajax图片上传,压缩保存到服务器

    thinkphp压缩图片插件官方地址 使用Composer安装ThinkPHP5的图像处理类库: composer require topthink/think-image 另外一种方法,传递base64图片,提交图片数据的字符串

    2024年02月07日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包