文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

小程序图片上传压缩

2023-09-18 15:16

关注

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

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

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

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

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

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

开发者可以通过控制 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)  }});

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

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

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

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

回顾常见的小程序业务场景,图片处理主要聚焦于用户上传图片、列表展示这 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

changeImage() {      // 图片限制大小      const fileLimit = 2 * 1024 * 1024      // 选择图片原图或是压缩图      const sizeType = this.data.isIos ? ['compressed'] : ['original', 'compressed']      wx.chooseMedia({        sizeType,        count: 9,        mediaType: ['image'],        sourceType: ['album', 'camera'],        success: async function (res) {          let tempFiles = res.tempFiles          if (tempFiles.length) {            for (let i = 0; i < tempFiles.length; i++) {              let filePath = tempFiles[i].tempFilePath              // 图片超过大小限制              if (tempFiles[i].size > fileLimit) {                // 手动压缩                filePath = await this.compressFile(filePath, i, tempFiles[i].size)              }              // 上传图片              wx.uploadFile({                url: 'xxx',                filePath,                name: 'xxx',                success: function (res) {                  // 图片上传成功                },                fail: function () {                  // 图片上传失败                }              })            }          }        }      })    },    // 压缩    compressFile(src, i, size) {      return new Promise((resolve) => {        // 获取图片信息        wx.getImageInfo({          src,          success: (img) => {            let imgWidth = img.width            let imgHeight = img.height            // 若宽高都小于4096,则使用canvas            if (imgWidth <= 4096 && imgHeight <= 4096) {              this.canvasToImg(src, i, imgWidth, imgHeight, size).then(res => {                resolve(res)              })            } else {              // 强制压缩              this.compressImage(src, size).then(res => {                resolve(res)              })            }          },          fail: () => {            this.compressImage(src, size).then(res => {              resolve(res)            })          }        })      })    },    // 绘制canvas    canvasToImg(src, i, imgWidth, imgHeight, size) {      return new Promise((resolve, reject) => {        const { pixelRatio, baseSize } = this.data  // baseSize设为1280,与图片宽高做比较        let query = wx.createSelectorQuery().in(this)        query.select(`#myCanvas${i}`)          .fields({ node: true, size: true })          .exec((res) => {            let canvas = res[0].node            if (!canvas) {              // 强制压缩              this.compressImage(src, size).then(res => {                resolve(res)              })              return            }            let ctx = canvas.getContext('2d')            let pic = canvas.createImage()            pic.src = src            let canvasWidth = 0            let canvasHeight = 0            let quality = 1            // 图片宽和高都小于基础值,则宽高不变,压缩质量为0.3,这里的基础值设为1280            if (imgWidth <= baseSize && imgHeight <= baseSize) {              canvasWidth = imgWidth              canvasHeight = imgHeight              quality = .3            } else {              let compareFlag = true              // 手机宽高比大于2,图片一边大于基础值,一边小于基础值,则宽高不变,压缩质量为0.3              if (pixelRatio > 2 && (imgWidth < baseSize || imgHeight < baseSize) && (imgWidth > baseSize || imgHeight > baseSize)) {                canvasWidth = imgWidth                canvasHeight = imgHeight                quality = .3              } else {                // 手机宽高比大于2,宽高最小值设为基础值,另一边等比缩放,手机宽高比小于等于2,宽高最大值设为基础值,另一边等比缩放,压缩质量为0.9                compareFlag = pixelRatio > 2 ? (imgWidth > imgHeight) : (imgWidth < imgHeight)                canvasWidth = compareFlag ? parseInt(imgWidth / (imgHeight / baseSize)) : baseSize                canvasHeight = compareFlag ? baseSize : parseInt(imgHeight / (imgWidth / baseSize))                quality = .9              }            }            // 设置canvas宽高            canvas.width = canvasWidth            canvas.height = canvasHeight            pic.onerror = () => {              // 图片加载失败则继续强制压缩              this.compressImage(src, size).then(response => {                resolve(response)              })            }            pic.onload = () => {              ctx.clearRect(0, 0, canvasWidth, canvasHeight);              ctx.drawImage(pic, 0, 0, canvasWidth, canvasHeight)              wx.canvasToTempFilePath({                canvas,                quality,                fileType: 'jpg',                width: canvasWidth,                height: canvasHeight,                destWidth: canvasWidth,                destHeight: canvasHeight,                success: resp => {                  // 生成的图片临时文件路径                  resolve(resp.tempFilePath)                  ctx.clearRect(0, 0, canvasWidth, canvasHeight);                },                fail: () => {                  this.compressImage(src, size).then(response => {                    resolve(response)                  })                }              })            }          })      })    },    // 强制压缩    compressImage(src, size) {      return new Promise((resolve, reject) => {        let quality = 100        // ios因为自己有压缩机制,压缩到极致就不会再压,因此往小了写        if (this.data.isIOS) {          quality = 0.1        } else {          let temp = 30 - parseInt(size / 1024 / 1024)          quality = temp < 10 ? 10 : temp        }        wx.compressImage({          src, // 图片路径          quality, // 压缩质量          success: function (res) {            resolve(res.tempFilePath)          },          fail: function (err) {            resolve(src)          }        })      })    },

每种图片处理方式都有其突出的优势,结合多种方式能够最优地解决问题,适用于目标场景,便利用户上传图片的体验。

来源地址:https://blog.csdn.net/qq_40850839/article/details/131287452

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯