微信小程序对图片进行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 相关文章推荐
基于jQuery的图片大小自动适应实现代码
Nov 17 Javascript
jQuery中的.bind()、.live()和.delegate()之间区别分析
Jun 08 Javascript
javascript时间函数基础介绍
Mar 28 Javascript
jQuery图片滚动图片的效果(另类实现)
Jun 02 Javascript
jquery将一个表单序列化为一个对象的方法
Dec 02 Javascript
Jquery插件实现点击获取验证码后60秒内禁止重新获取
Mar 13 Javascript
Jquery判断radio、selelct、checkbox是否选中及获取选中值方法总结
Apr 15 Javascript
Angularjs中UI Router的使用方法
May 14 Javascript
RequireJs的使用详解
Feb 19 Javascript
JS数组去重常用方法实例小结【4种方法】
May 28 Javascript
详解小程序如何避免多次点击,重复触发事件
Apr 08 Javascript
插件导致ECharts被全量引入的坑示例解析
Sep 23 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关联数组快速排序的方法
2015/04/17 PHP
php使用Jpgraph创建3D饼形图效果示例
2017/02/15 PHP
js split 的用法和定义 js split分割字符串成数组的实例代码
2012/05/13 Javascript
Node.js(安装,启动,测试)
2014/06/09 Javascript
jQuery控制Div拖拽效果完整实例分析
2015/04/15 Javascript
JavaScript对象数组排序函数及六个用法
2015/12/23 Javascript
js简单判断flash是否加载完成的方法
2016/06/21 Javascript
学习Bootstrap滚动监听 附调用方法
2016/07/02 Javascript
AngularJS 模型详细介绍及实例代码
2016/07/27 Javascript
彻底学会Angular.js中的transclusion
2017/03/12 Javascript
Angular.js指令学习中一些重要属性的用法教程
2017/05/24 Javascript
vue父组件通过props如何向子组件传递方法详解
2017/08/16 Javascript
Vue2.0 实现歌手列表滚动及右侧快速入口功能
2018/08/08 Javascript
jQuery实现提交表单时不提交隐藏div中input的方法
2019/10/08 jQuery
js cavans实现静态滚动弹幕
2020/05/21 Javascript
Vue+Openlayers自定义轨迹动画
2020/09/24 Javascript
Python学习笔记之常用函数及说明
2014/05/23 Python
Django的数据模型访问多对多键值的方法
2015/07/21 Python
Python的collections模块中namedtuple结构使用示例
2016/07/07 Python
获取python文件扩展名和文件名方法
2018/02/02 Python
对python csv模块配置分隔符和引用符详解
2018/12/12 Python
详解Python IO口多路复用
2020/06/17 Python
用CSS3来实现社交分享按钮
2014/11/11 HTML / CSS
C语言笔试题回忆
2015/04/02 面试题
介绍一下HDLC(High-Level Data Link Control)高层数据链路协议
2012/01/21 面试题
企业管理毕业生求职信范文
2014/03/07 职场文书
领导班子奢靡之风查摆问题及整改措施
2014/09/27 职场文书
幼儿园2014年度工作总结
2014/11/10 职场文书
青年教师个人总结
2015/02/11 职场文书
师范生见习总结范文
2015/06/23 职场文书
党校团干班培训心得体会
2016/01/06 职场文书
导游词之河姆渡遗址博物馆
2019/10/10 职场文书
css3 filter属性的使用简介
2021/03/31 HTML / CSS
浅谈Python列表嵌套字典转化的问题
2021/04/07 Python
python文件名批量重命名脚本实例代码
2021/04/22 Python
Python OpenCV超详细讲解基本功能
2022/04/02 Python