微信小程序开发指南之图片压缩解决方案

目录
  • 前言:
  • 问题:现有的压缩方案支付宝小程序不生效
  • 解决方案:
  • 核心代码展示:
  • 附:微信小程序图片压缩(支持多张图)
  • 小结:

前言:

由于公司业务拓展,急需基于uniapp生成支付宝小程序。之前已经成功将微信小程序和H5融合成一套码,故得知此需求的时候,笔者信心十足,但是本着实践出真知的想法,觉得还是得先调研一下uniapp在支付宝小程序的兼容性,并集成已有项目主体关键功能,为后续的技术调研方案做准备。在调研过程中,发现之前封装好的图片压缩方法在支付宝小程序上无法正常使用,重新阅读了官方文档后,又双更新了项目的图片压缩方法的使用流程。

问题:现有的压缩方案支付宝小程序不生效

之前封装好的压缩方案,原理是使用canvas现实的,但是在支付宝小程序端不生效,canvas相关的api存在但是不可用。

解决方案:

查阅文档后,给canvas添加了id区分支付宝小程序,可兼容之。

以下是官方文档原文

uni.createCanvasContext(canvasId, this)

#定义

画布表示,传入定义在 <canvas/> 的 canvas-id或id(支付宝小程序是id、其他平台是canvas-id)

核心代码展示:

1,封装公用工具类compressImage.js

/**
 * 给的文件资源是否小于LimitSize (M), 小于走lessCallBack, 大于走moreCallBack
 */
export function imageSizeIsLessLimitSize(imagePath, limitSize, lessCallBack, moreCallBack) {
  uni.getFileInfo({
    filePath: imagePath,

    success(res) {
      console.log('压缩前图片大小:', res.size / 1024, 'kb')

      if (res.size > 1024 * 1024 * limitSize) {
        moreCallBack()
      } else {
        lessCallBack()
      }
    }
  })
} // 主调用方法

/**
 * 获取小于限制大小的Image, limitSize默认为1M,递归调用。
 */

export function getLessLimitSizeImage(canvasId, imagePath, limitSize = 1, drawWidth, callBack) {
  imageSizeIsLessLimitSize(
    imagePath,
    limitSize,
    (lessRes) => {
      callBack(imagePath)
    },
    (moreRes) => {
      uni.getImageInfo({
        src: imagePath,
        success: function(imageInfo) {
          var maxSide = Math.max(imageInfo.width, imageInfo.height) //画板的宽高默认是windowWidth

          var windowW = drawWidth
          var scale = 1

          if (maxSide > windowW) {
            scale = windowW / maxSide
          }

          var imageW = Math.floor(imageInfo.width * scale)
          var imageH = Math.floor(imageInfo.height * scale)
          console.log('调用压缩', imageW, imageH)
          getCanvasImage(canvasId, imagePath, imageW, imageH, (pressImgPath) => {
            getLessLimitSizeImage(canvasId, pressImgPath, limitSize, drawWidth * 0.7, callBack)
          })
        }
      })
    }
  )
}
/**
 * 获取画布图片
 */

export function getCanvasImage(canvasId, imagePath, imageW, imageH, getImgsuccess) {
  const ctx = uni.createCanvasContext(canvasId)
  ctx.drawImage(imagePath, 0, 0, imageW, imageH)
  ctx.draw(false, () => {
    uni.canvasToTempFilePath({
      canvasId: canvasId,
      x: 0,
      y: 0,
      width: imageW,
      height: imageH,
      quality: 1,

      success(res) {
        getImgsuccess(res.tempFilePath)
      }
    })
  })
}
export default {
  getLessLimitSizeImage,
  imageSizeIsLessLimitSize,
  getCanvasImage
}

2,html调用并上传服务器:

<template>
  <view class="upload-page">
    <view class="upload-tips">您最多可上传{{maxCount}}张图片</view>
    <view class="image-list">
      <view v-for="(item, index) in fileList"
            :key="index"
            class="image-item">
        <image class="image"
               mode="aspectFit"
               :src="item.path"
               @click="viewImage(index)"></image>
        <image class="image-delete"
               :src="imgUrl + 'doctor/img_delete.png'"
               @tap.stop="deleteImage"
               :data-index="index"></image>
      </view>
      <view v-if="fileList.length < maxCount"
            class="image-item"
            @tap="openAlbum">
        <image class="image"
               :src="imgUrl + 'doctor/img_add.png'"></image>
      </view>
    </view>
    <view class="upload-btn"
          @tap="confirmUpload">确定</view>

    <canvas canvas-id="pressCanvas"
            id="pressCanvas"
            class="press-canvas"></canvas>
  </view>
</template>

<script>
import { getLessLimitSizeImage } from './compressImage.js'

export default {
  data() {
    return {
      imgUrl: process.env.VUE_APP_RESOURCE_URL,
      page: {
        json: {}
      },
      type: '',
      fileList: [],
      maxCount: 9
    }
  },

  components: {},
  props: {},

  onLoad(options) {
    this.type = options.type
    this.page.json = options
  },

  methods: {
    confirmUpload() {
      if (this.fileList.length === 0) {
        this.$util.showToast('请至少选择一张图片')
        return false
      }
      this.$Router.back()
      uni.$emit(this.page.json.emit, this.fileList)
    },

    // 查看图片
    viewImage(index) {
      let copyData = [],
        data = [].concat(this.fileList)
      data.forEach((v) => {
        copyData.push(v.path)
      })
      uni.previewImage({
        current: copyData[index],
        urls: copyData
      })
    },

    // 删除图片
    deleteImage(e) {
      let { index } = e.currentTarget.dataset
      this.fileList.splice(index, 1)
    },

    // 打开相册
    openAlbum() {
      let length = this.maxCount - this.fileList.length
      uni.chooseImage({
        count: length,
        sizeType: ['original', 'compressed'],
        sourceType: ['album', 'camera'],
        success: (res) => {
          this.upLoadImgs(res.tempFilePaths, this.type)
        }
      })
    },

    // 上传多张图片
    upLoadImgs(files, type) {
      uni.showLoading()
      let promises = files.map((item) => {
        return this.uploadImg(item, type)
      })
      Promise.all(promises)
        .then((datas) => {
          // 所有上传完成后
          this.fileList = datas.length > 0 && this.fileList.concat(datas)

          uni.hideLoading()
        })
        .catch(() => {
          uni.hideLoading()
        })
    },

    // 上传图片
    uploadImg(file, type) {
      return new Promise((resolve, reject) => {
        getLessLimitSizeImage('pressCanvas', file, 1, 750, (imagePath) => {
          /* #ifdef H5 */
          let devicetype = 'h5'
          /* #endif */
          /* #ifdef MP-WEIXIN */
          let devicetype = 'applet'
          /* #endif */

          /* #ifdef MP-ALIPAY */
          let devicetype = 'alipay'
          /* #endif */

          uni.uploadFile({
            url: process.env.VUE_APP_API_URL + 'client/v1/file/images',
            header: {
              'access-token': this.$store.state.user.accessToken,
              version: process.env.VUE_APP_VERSION,
              'version-code': process.env.VUE_APP_VERSION_CODE,
              devicetype: devicetype
            },
            fileType: 'image',
            filePath: imagePath,
            name: 'file',
            formData: {
              source: 'inquiryApply',
              type:  ''
            },
            success: (res) => {
              let image = JSON.parse(res.data)
              console.log('uploadFile success:', image)

              if (image.code === 200) {
                resolve(image.data[0])
              } else {
                this.$util.showModal(image.msg || '图片上传失败')
                reject(image)
              }
            },
            fail: (err) => {
              console.log('uploadFile fail:', JSON.stringify(err || {}))

              if (err.hasOwnProperty('errMsg') && err.errMsg.indexOf('timeout') > 0) {
                this.$util.showModal('上传超时,请稍后再试')
              } else {
                this.$util.showModal('图片上传失败,请稍后再试')
              }

              reject(err)
            },
            complete: () => {}
          })
        })
      })
    }
  }
}
</script>
<style lang="scss" scoped>
.upload-page {
  position: relative;
  width: 750rpx;
  height: 100vh;
  background-color: #ffffff;
}

.upload-tips {
  width: 750rpx;
  height: 80rpx;
  background-color: #fffbe8;
  font-size: 28rpx;
  color: #ed6a0c;
  line-height: 80rpx;
  text-align: center;
}

.image-list {
  box-sizing: border-box;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  align-items: center;
  width: 750rpx;
  padding: 30rpx;
}

.image-item {
  position: relative;
  box-sizing: border-box;
  width: 210rpx;
  height: 210rpx;
  margin-right: 30rpx;
  margin-bottom: 30rpx;
  border: 1rpx solid #ebedf0;
}

.image-item:nth-child(3n) {
  margin-right: 0;
}

.image-item .image {
  width: 210rpx;
  height: 210rpx;
}

.image-item .image-delete {
  position: absolute;
  top: -30rpx;
  right: -30rpx;
  width: 40rpx;
  height: 40rpx;
  padding: 10rpx;
}

.upload-btn {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 750rpx;
  height: 100rpx;
  background-color: $primary;
  font-size: 30rpx;
  color: #ffffff;
  line-height: 100rpx;
  text-align: center;
}

.press-canvas {
  position: absolute;
  top: -1000px;
  left: -1000px;
  background-color: gray;
  width: 750px;
  height: 750px;
}
</style>

附:微信小程序图片压缩(支持多张图)

原理上是使用canvas实现的,小于100k的图片不做压缩。

var {getCanvasImg} = require('../../common/img-compression.js'); // 在page上面按需引入

然后在wx.chooseImage接口成功回调中调用(使用tempFiles字段,因为它包含了图片大小)

let tempFiles = result.tempFiles;
let i = 0;
var arr = [];
// par1:this; par2:图片压缩数组,含size字段;par3:递增值,默认先传入0; par4:接收压缩结果数组; par5:设置画布大小回调函数; par6:设置压缩后的图片数组
getCanvasImg(that, tempFiles, i, that.data.quality, arr, that.setCanvasSize, that.setCompImg);

在定义两个回调函数,用于设置画布大小和接收压缩结果

// 设置画布大小
setCanvasSize(cWidth, cHeight){
    this.setData({
      cWidth,
      cHeight
    });
  },
  // 接收压缩结果
  setCompImg(imagePath){
    this.setData({
      imagePath // 压缩结果
    })
  },

至此使用步骤已介绍完毕

小结:

以上就是笔者分享的图片压缩上传的方法封装及使用啦,完美兼容支付宝小程序,微信小程序及H5三端。

到此这篇关于微信小程序开发指南之图片压缩解决方案的文章就介绍到这了,更多相关微信小程序图片压缩内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 微信小程序上传图片并等比列压缩到指定大小的实例代码

    微信小程序官方API中 wx.chooseImage() 是可以进行图片压缩的,可惜的是不能压缩到指定大小. 实际开发中需求可能是压缩到指定大小: 原生js可以使用canvas来压缩,但由于微信小程序对canvas有封装,使得利用canvas来压缩图片有了一些区别: 代码放在了git:https://github.com/jonyellow/code-diary/tree/master/%E5%B0%8F%E7%A8%8B%E5%BA%8F/%E5%9B%BE%E7%89%87%E5%8E%8B

  • 微信小程序实现图片压缩

    本文实例为大家分享了微信小程序图片压缩的具体代码,供大家参考,具体内容如下 设计思路: 选择图片后调用微信压缩图片接口,压缩后接收压缩图片的临时地址,调用微信储存接口保存图片至本地. 参数: imagesrc:图片地址 imgcount:是否选择图片 show_hidden:是否展示按钮 接口: wx.chooseImage:选择图片 wx.compressImage:压缩图片 wx.saveImageToPhotosAlbum:保存图片至相册 wx.showToast:提示信息 wxml <v

  • 微信小程序对图片进行canvas压缩的方法示例详解

    微信小程序其实自带一个图片压缩的API wx.compressImage,但是这玩意目前感受就是个垃圾.IOS大多数情况下据说还可以,安卓有的时候降低质量压缩后体积反而变大,而且没办法控制其压缩至具体指定的大小,压缩后多大看天意.所以需要使用画布去自己实现一个图片压缩方法. 简单来讲原理就是:找个不显示在页面上的画布画上去,再取出,如果体积还是太大,缩小尺寸后再画,再取,递归下去,直到体积满足要求.(所以限制的越小,图片越大,压缩越久,递归次数越多) 第一步:新建一个zipPic.js文件(名字

  • 微信小程序之批量上传并压缩图片的实例代码

    具体内容如下所示: 首先,要在.wxml文件里面创建一个canvas,作用是承载压缩的图片,以供上传的时候获取 这个canvas不能隐藏,否则没效果,可以将其移至屏幕外. <canvas canvas-id='attendCanvasId' class='myCanvas'></canvas> 然后呢,就是.js文件里面的方法了 // 点击加_压缩 takePhoto: function () { var that = this; let imgViewList = that.da

  • 微信小程序实现图片压缩功能

    小龙大哥的微信小程序在初始阶段相当于IE界的6,在这里给大家说一个刚趟过去的坑. 拍照的API. wx.chooseImage({ count: 1, // 默认9 sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有 sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有 success: function (res) { // 返回选定照片的本地文件路径列表,temp

  • 微信小程序中上传图片并进行压缩的实现代码

    小程序上传图片要先了解他其中的各个属性值,在https://developers.weixin.qq.com/miniprogram/dev/api/media-picture.html内有详细的介绍 今天在这里主要来讲下如何去上传图片并进行压缩,了解下以下属性值 先来看下页面展示(点击上传图片,从相册中选择,上传完图片后又点了一次上传) 来来来,上代码 wxml代码 <button bindtap='chooseImageTap'>上传图片</button> <button

  • 微信小程序开发指南之图片压缩解决方案

    目录 前言: 问题:现有的压缩方案支付宝小程序不生效 解决方案: 核心代码展示: 附:微信小程序图片压缩(支持多张图) 小结: 前言: 由于公司业务拓展,急需基于uniapp生成支付宝小程序.之前已经成功将微信小程序和H5融合成一套码,故得知此需求的时候,笔者信心十足,但是本着实践出真知的想法,觉得还是得先调研一下uniapp在支付宝小程序的兼容性,并集成已有项目主体关键功能,为后续的技术调研方案做准备.在调研过程中,发现之前封装好的图片压缩方法在支付宝小程序上无法正常使用,重新阅读了官方文档后

  • 微信小程序 开发指南详解

    编写代码 创建小程序实例 点击开发者工具左侧导航的"编辑",我们可以看到这个项目,已经初始化并包含了一些简单的代码文件.最关键也是必不可少的,是 app.js.app.json.app.wxss 这三个.其中,.js后缀的是脚本文件,.json后缀的文件是配置文件,.wxss后缀的是样式表文件.微信小程序会读取这些文件,并生成小程序实例. 下面我们简单了解这三个文件的功能,方便修改以及从头开发自己的微信小程序. ​ app.js是小程序的脚本代码.我们可以在这个文件中监听并处理小程序的

  • 微信小程序开发图片拖拽实例详解

    微信小程序开发图片拖拽实例详解 1.编写页面结构:moveimg.wxml <view class="container"> <view class="cnt"> <image class="image-style" src="../uploads/foods.jpg" style="left:{{ballleft}}px;width:{{screenWidth}}px" bi

  • 详解微信小程序开发聊天室—实时聊天,支持图片预览

    第一次写小程序,老板就让我用websoket写个聊天对话,群聊这种.第一次写聊天功能,第一次用websoket,第一次用小程序,这是在考验我吗?不过我还是研究了一下,终于实现了. 首先看一下界面,界面很简单,就是首页刚进来获取了用户信息头像,昵称等.点击进入聊天室就可以聊天了,下面我介绍的是前端代码实现,后台需要做的很简单,就是你给他发送什么数据,他就给你返回什么数据,就是在接收前台发送过来的图片的时候需要做个格式转换,因为有时候前端将接收到的json字符串转换json对象的时候,遇到有特殊的标

  • 微信小程序开发实战快速入门教程

    目录 注册微信小程序 微信开发者工具 第一个小程序 新建项目 项目目录结构 目标成果 步骤分解 页头页尾 个人中心 生活指南 模拟弹窗 预览图片 注册微信小程序 如果你还没有微信公众平台的账号,请先进入微信公众平台首页,点击 “立即注册” 按钮进行注册.注册的账号类型可以是订阅号.服务号.小程序以及企业微信,我们选择 “小程序” 即可. 接着填写账号信息,需要注意的是,填写的邮箱必须是未被微信公众平台注册.未被个人微信号绑定的邮箱,而且每个邮箱仅能申请一个小程序. 激活邮箱之后,选择主体类型为

  • 微信小程序开发之选项卡(窗口底部TabBar)页面切换

    微信小程序开发中窗口底部tab栏切换页面很简单很方便. 代码: 1.app.json //app.json { "pages":[ "pages/index/index", "pages/logs/logs" ], "window":{ "backgroundTextStyle":"light", "navigationBarBackgroundColor": &qu

  • 微信小程序-拍照或选择图片并上传文件

    微信小程序-拍照或选择图片并上传文件 调用拍照API:https://mp.weixin.qq.com/debug/wxadoc/dev/api/media-picture.html?t=20161222#wxchooseimageobject 上传文件API:https://mp.weixin.qq.com/debug/wxadoc/dev/api/network-file.html 主要js代码: choice: function () { var that = this wx.choose

  • 微信小程序教程之本地图片上传(leancloud)实例详解

    微信小程序 leancloud --本地图片上传 由于本站最近学习微信小程序的知识,这里记录下微信小程序实现本地上传的功能实现方法,以下是网上找的资料,大家看下. 将本地图片上传至leancloud后台. 获取本地图片或者拍照,我在上一篇博文中写过.这里就不说了.我的博客 直接上代码: 1.index.js //index.js //获取应用实例 var app = getApp() const AV = require('../../utils/av-weapp.js'); Page({ da

  • 微信小程序 开发中遇到问题总结

    微信小程序 开发中遇到问题总结 1.由于小程序wx.request()方法是异步的,在app.js执行ajax后,各分页加载app.js的全局数据时,无法按顺序加载.例: //app.js App({ ajax:function(){ let that = this; wx.request({ url: 'https://a.com/url.php', method: 'GET', success: function(e){ that.data = 123; } }) }; }) //conte

  • 微信小程序实现image组件图片自适应宽度比例显示的方法

    本文实例讲述了微信小程序实现image组件图片自适应宽度比例显示的方法.分享给大家供大家参考,具体如下: 一. 了解image组件 由于image有默认的固定的宽度和高度,这样我们在做图片自适应的时候,就不好做了.下面就来一起解决下 二. 方法 (一).使用mode:widthFix widthFix:宽度不变,高度自动变化,保持原图宽高比不变. 首先我们先设置image的mode为widthFix,然后给图片加一个固定rpx的宽度,比如:730rpx. 这样图片也可以自适应了..因为小程序的r

随机推荐