微信小程序对图片进行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 创建Dom元素
May 07 Javascript
js局部刷新页面时间具体实现
Jul 04 Javascript
AngularJS中的过滤器使用详解
Jun 16 Javascript
javascript实现多栏闭合展开式广告位菜单效果实例
Aug 05 Javascript
获取阴历(农历)和当前日期的js代码
Feb 15 Javascript
微信开发之调起摄像头、本地展示图片、上传下载图片实例
Dec 08 Javascript
bootstarp modal框居中显示的实现代码
Feb 18 Javascript
AugularJS从入门到实践(必看篇)
Jul 10 Javascript
vue中的非父子间的通讯问题简单的实例代码
Jul 19 Javascript
React Native AsyncStorage本地存储工具类
Oct 24 Javascript
详解React中setState回调函数
Jun 14 Javascript
React精髓!一篇全概括小结(急速)
May 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” 彩蛋进行敏感信息获取
2013/08/07 PHP
PHP中isset()和unset()函数的用法小结
2014/03/11 PHP
phpstudy的php版本自由修改的方法
2017/10/18 PHP
tp5框架使用composer实现日志记录功能示例
2019/01/10 PHP
Jquery插件easyUi实现表单验证示例
2015/12/15 Javascript
javascript insertAfter()定义与用法示例
2016/07/25 Javascript
jQuery对table表格进行增删改查
2020/12/22 Javascript
微信小程序网络请求wx.request详解及实例
2017/05/18 Javascript
Vue源码学习之初始化模块init.js解析
2017/11/02 Javascript
js实现web调用摄像头 js截取视频画面
2019/04/21 Javascript
webpack HappyPack实战详解
2019/10/08 Javascript
JS立即执行的匿名函数用法分析
2019/11/04 Javascript
Vue事件处理原理及过程详解
2020/03/11 Javascript
vue实现导航菜单和编辑文本的示例代码
2020/07/04 Javascript
vue v-model的用法解析
2020/10/19 Javascript
python使用urllib2提交http post请求的方法
2015/05/26 Python
Python编程中对文件和存储器的读写示例
2016/01/25 Python
Python爬虫_城市公交、地铁站点和线路数据采集实例
2018/01/10 Python
1分钟快速生成用于网页内容提取的xslt
2018/02/23 Python
让Django支持Sql Server作后端数据库的方法
2018/05/29 Python
Python 对输入的数字进行排序的方法
2018/06/23 Python
Scrapy框架爬取西刺代理网免费高匿代理的实现代码
2019/02/22 Python
详解python运行三种方式
2019/05/13 Python
Python中字符串与编码示例代码
2019/05/20 Python
33个Python爬虫项目实战(推荐)
2019/07/08 Python
Pytorch损失函数nn.NLLLoss2d()用法说明
2020/07/07 Python
css3发光搜索表单分享
2014/04/11 HTML / CSS
10分钟理解CSS3 Grid布局
2018/12/20 HTML / CSS
Html5实现iPhone开机界面示例代码
2013/06/30 HTML / CSS
中秋晚会策划方案
2014/06/12 职场文书
忠诚奉献演讲稿
2014/09/12 职场文书
2014年基层党建工作总结
2014/11/11 职场文书
2014年医院工作总结
2014/11/20 职场文书
MySQL入门命令之函数-单行函数-流程控制函数
2021/04/05 MySQL
详细谈谈MYSQL中的COLLATE是什么
2021/06/11 MySQL
为什么代码规范要求SQL语句不要过多的join
2021/06/23 MySQL