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


Posted in Javascript onNovember 12, 2020

微信小程序其实自带一个图片压缩的API wx.compressImage,但是这玩意目前感受就是个垃圾。IOS大多数情况下据说还可以,安卓有的时候降低质量压缩后体积反而变大,而且没办法控制其压缩至具体指定的大小,压缩后多大看天意。所以需要使用画布去自己实现一个图片压缩方法。

简单来讲原理就是:找个不显示在页面上的画布画上去,再取出,如果体积还是太大,缩小尺寸后再画,再取,递归下去,直到体积满足要求。(所以限制的越小,图片越大,压缩越久,递归次数越多)

第一步:新建一个zipPic.js文件(名字你开心就好),里面的代码如下

//通过canvas将图片压缩至指定大小

//判断图片大小是否满足需求,limitSize的单位是kb
function imageSizeIsLessLimitSize(imagePath,limitSize,lessCallback,moreCallback){
 //获取文件信息
 wx.getFileInfo({
 filePath:imagePath,
 success:(res)=>{
  console.log("压缩前图片大小",res.size/1024,'kb');
  //如果图片太大了走moreCallback
  if(res.size>1024*limitSize){
  moreCallback()
  }
  //图片满足要求了走lessCallback
  else{
  lessCallback()
  }
 }
 })
}

//将图片画在画布上并获取画好之后的图片的路径
function getCanvasImage(canvasId,imagePath,imageW,imageH,getImgSuccess){
 //创建画布内容
 const ctx=wx.createCanvasContext(canvasId);
 //图片画上去,imageW和imageH是画上去的尺寸,图像和画布间隔都是0
 ctx.drawImage(imagePath,0,0,imageW,imageH);
 //这里一定要加定时器,给足够的时间去画(所以每次递归最少要耗时200ms,多次递归很耗时!)
 ctx.draw(false,setTimeout(function(){
 wx.canvasToTempFilePath({
  canvasId:canvasId,
  x:0,
  y:0,
  width:imageW,
  height:imageH,
  quality:1, //最高质量,只通过尺寸放缩去压缩,画的时候都按最高质量来画
  success:(res)=>{
  getImgSuccess(res.tempFilePath);
  }
 })
 },200));
}

//主函数,默认限制大小1024kb即1mb,drawWidth是绘画区域的大小
//初始值传入为画布自身的边长(我们这是一个正方形的画布)
function getLessLimitSizeImage(canvasId,imagePath,limitSize=1024,drawWidth,callback){
 //判断图片尺寸是否满足要求
 imageSizeIsLessLimitSize(imagePath,limitSize,
 (lessRes)=>{
  //满足要求走callback,将压缩后的文件路径返回
  callback(imagePath);
 },
 (moreRes)=>{
  //不满足要求需要压缩的时候
  wx.getImageInfo({
  src:imagePath,
  success:(imageInfo)=>{
   let maxSide=Math.max(imageInfo.width,imageInfo.height);
   let windowW=drawWidth;
   let scale=1;
   /*
   这里的目的是当绘画区域缩小的比图片自身尺寸还要小的时候
   取图片长宽的最大值,然后和当前绘画区域计算出需要放缩的比例
   然后再画经过放缩后的尺寸,保证画出的一定是一个完整的图片。由于每次递归绘画区域都会缩小,
   所以不用担心scale永远都是1绘画尺寸永远不变的情况,只要不满足压缩后体积的要求
   就会缩小绘画区域,早晚会有绘画区域小于图片尺寸的情况发生
   */
   if(maxSide>windowW){
   scale=windowW/maxSide;
   }
   //trunc是去掉小数
   let imageW=Math.trunc(imageInfo.width*scale);
   let imageH=Math.trunc(imageInfo.height*scale);
   console.log('调用压缩',imageW,imageH);
   //图片在规定绘画区域上画并获取新的图片的path
   getCanvasImage(canvasId,imagePath,imageW,imageH,
   (pressImgPath)=>{
    /*
    再去检查是否满足要求,始终缩小绘画区域,让图片适配绘画区域
    这里乘以0.95是必须的,如果不缩小绘画区域,会出现尺寸比绘画区域小,
    而体积比要求压缩体积大的情况出现,就会无穷递归下去,因为scale的值永远是1
    但0.95不是固定的,你可以根据需要自己改,0到1之间,越小则绘画区域缩小的越快
    但不建议取得太小,绘画区域缩小的太快,压出来的将总是很糊的
    */
    getLessLimitSizeImage(canvasId,pressImgPath,limitSize,drawWidth*0.95,callback);
   }
   )
  }
  })
 }
 )
}

export default getLessLimitSizeImage

好的接下来是使用的方法:

在你想压缩图片的js代码所对应的页面中。先放置一个用户看不见的画布。

(就是如果我想在index.js中chooseImage再压缩,就需要你在index.html中加上下面的html代码)

<!--用于图片压缩的canvas画布,不在页面中展示,且id固定不可变-->
 <canvas
 style="width: {{cw}}px; height: {{cw}}px;position: absolute; z-index: -1; left: -10000rpx;; top: -10000rpx;"
 canvas-id="zipCanvas"
 ></canvas>
 <!--画布结束-->

其中cw的值我个人建议选择用户屏幕的宽度,如下,在page({…})的data中添加

//画板边长默认是屏幕宽度,正方形画布
 cw:wx.getSystemInfoSync().windowWidth,

个人建议画布和绘画区域都是正方形的,毕竟你也不知道要压缩的图片是横向的还是纵向的。

然后,引入,不解释

import getLessLimitSizeImage from '../../utils/zipPic'

在js代码中:

wx.chooseImage({
  count:1, //只传一张
  sizeType:'original', //原图质量好,然后通过canvas压缩,缩略图压缩就太糊了
  sourceType: ['album', 'camera'], // 来源是相册和相机
  success:(res)=>{
  let canvasId='zipCanvas' //注意这里的id和你在页面中写的html代码的canvas的id要一致
  let imagePath=res.tempFilePaths[0];//原图的路径
  let limitSize=2048;//大小限制2048kb
  let drawWidth=wx.getSystemInfoSync().windowWidth;//初始绘画区域是画布自身的宽度也就是屏幕宽度
  wx.showLoading({title:'图片压缩中...',mask:true}) //不需要你可以删掉
  getLessLimitSizeImage(canvasId,imagePath,limitSize,drawWidth,(resPath)=>{
   wx.hideLoading(); //不需要你可以删掉
   
   //resPath就是压缩后图片的路径,然后想做什么都随你
   
  })
  }
 })

补充:

  1. 这里代码的主体不是我做的,网上一搜基本都是这个写法,这里是经过项目实践测试后没问题了做的讲解。
  2. 这里图片是只选了一张去压缩,如果你需要选多张再挨个压缩那就去写个循环,找个数组存压缩后的结果,网上也有很多内容。
  3. 回调函数中有lessRes和moreRes,细心的会发现这两个参数并没有被用到,他们只是个提醒作用,表明当前是less回调还是more回调,如果你不怕弄混删掉了或者自己另外写了两个新方法那都随你。
  4. 极限情况下比如说将图片强制压缩至10kb,这个东西我没测试过,不知道会不会有问题。
  5. 图片压缩体积的减小不是线性的,给人的感觉有点像二次函数(y=x^2左面那一半),越往后压缩的尺寸变化会越小。当然,这和用户的分辨率,屏幕本身的大小都有关系。
  6. 还是那句话,由于每次递归都要给至少200ms的时间去画,所以递归很耗时!!!而不递归进行压缩的话,网络传输又会很耗时!!!所以这个地方怎么取舍,压缩至多大,绘画区域缩小的多快,都要靠你自己的经验去调试。
  7. 图片的压缩,长宽比理论上来讲是不变的,但是因为舍弃了小数,可能会有肉眼难以察觉的误差,但是问题不大。如果前端想展示一下压缩后的图片的话,不要忘记在image中加入mode=“aspectFit” 。

到此这篇关于微信小程序对图片进行canvas压缩的文章就介绍到这了,更多相关微信小程序对图片canvas压缩内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
bcastr2.0 通用的图片浏览器
Nov 22 Javascript
JavaScript 组件之旅(一)分析和设计
Oct 28 Javascript
jQuery 美元符冲突的解决方法
Mar 28 Javascript
基于JQuery的多标签实现代码
Sep 19 Javascript
JS中setTimeout()的用法详解
Apr 14 Javascript
JS获取计算机mac地址以及IP的实现方法
Jan 08 Javascript
JavaScript常用脚本汇总(三)
Mar 04 Javascript
一个炫酷的Bootstrap导航菜单
Dec 28 Javascript
基于vue实现分页效果
Nov 06 Javascript
浅谈Angularjs中不同类型的双向数据绑定
Jul 16 Javascript
vue-cli 脚手架基于Nightwatch的端到端测试环境的过程
Sep 30 Javascript
微信小程序如何获取地址
Dec 24 Javascript
解决vuex改变了state的值,但是页面没有更新的问题
Nov 12 #Javascript
javascript实现搜索筛选功能实例代码
Nov 12 #Javascript
vue实现两个组件之间数据共享和修改操作
Nov 12 #Javascript
vue 解决mintui弹窗弹起来,底部页面滚动bug问题
Nov 12 #Javascript
vue打包通过image-webpack-loader插件对图片压缩优化操作
Nov 12 #Javascript
详解ES6 扩展运算符的使用与注意事项
Nov 12 #Javascript
在vue中使用image-webpack-loader实例
Nov 12 #Javascript
You might like
基于PHP一些十分严重的缺陷详解
2013/06/03 PHP
PHP Smarty模版简单使用方法
2016/03/30 PHP
php把时间戳转换成多少时间之前函数的实例
2016/11/16 PHP
JavaScript delete操作符应用实例
2009/01/13 Javascript
jQuery计算textarea中文字数(剩余个数)的小程序
2013/11/28 Javascript
jQuery 浮动导航菜单适合购物商品类型的网站
2014/09/09 Javascript
Jquery实现textarea根据文本内容自适应高度
2015/04/03 Javascript
js+html5获取用户地理位置信息并在Google地图上显示的方法
2015/06/05 Javascript
jQuery3.0中的buildFragment私有函数详解
2016/08/16 Javascript
JavaScript基于对象去除数组重复项的方法
2016/10/09 Javascript
jquery仿ps颜色拾取功能
2017/03/08 Javascript
nodejs个人博客开发第六步 数据分页
2017/04/12 NodeJs
使用express搭建一个简单的查询服务器的方法
2018/02/09 Javascript
解决vue2中使用axios http请求出现的问题
2018/03/05 Javascript
javascript(基于jQuery)实现鼠标获取选中的文字示例【测试可用】
2019/10/26 jQuery
Electron实现应用打包、自动升级过程解析
2020/07/07 Javascript
Python字符转换
2008/09/06 Python
Python简单实现查找一个字符串中最长不重复子串的方法
2018/03/26 Python
使用Python监控文件内容变化代码实例
2018/06/04 Python
python实现图片批量压缩程序
2018/07/23 Python
python pandas写入excel文件的方法示例
2019/06/25 Python
Python数据分析模块pandas用法详解
2019/09/04 Python
Python爬虫之urllib基础用法教程
2019/10/12 Python
Python操作SQLite/MySQL/LMDB数据库的方法
2019/11/07 Python
Pytorch中实现只导入部分模型参数的方式
2020/01/02 Python
python如何代码集体右移
2020/07/20 Python
Html5 web本地存储实例详解
2016/07/28 HTML / CSS
幼儿园实习自我鉴定
2013/12/15 职场文书
自荐书模板
2013/12/15 职场文书
新学期红领巾广播稿
2014/01/14 职场文书
推普周活动总结
2014/08/28 职场文书
电子银行业务授权委托书
2014/10/10 职场文书
离婚协议书范本及离婚须知
2014/10/15 职场文书
教师节倡议书2015
2015/04/27 职场文书
《画家和牧童》教学反思
2016/02/17 职场文书
从原生JavaScript到React深入理解
2022/07/23 Javascript