vue2实现移动端上传、预览、压缩图片解决拍照旋转问题


Posted in Javascript onApril 13, 2017

因为最近遇到个移动端上传头像的需求,上传到后台的数据是base64位,其中为了提高用户体验,把比较大的图片用canvas进行压缩之后再进行上传。在移动端调用拍照功能时,会发生图片旋转,为了解决这个问题引入了exif去判断拍照时的信息再去处理图片,这是个很好的插件。关于exif.js可以去他的GitHub上了解,这边直接 npm install exif-js --save   安装,然后import一下就可以使用了。以下就是源码,可以直接使用。

<template> 
 <div> 
 <div style="padding:20px;"> 
 <div class="show"> 
 <div class="picture" :style="'backgroundImage:url('+headerImage+')'"></div> 
 </div> 
 <div style="margin-top:20px;"> 
 <input type="file" id="upload" accept="image" @change="upload"> 
 <label for="upload"></label> 
 </div> 
 </div> 
 </div> 
</template> 
<script> 
import Exif from 'exif-js' 
export default { 
 data () { 
 return { 
 headerImage:'', 
 } 
 }, 
 mounted () { 
 }, 
 methods: { 
 upload (e) { 
 let files = e.target.files || e.dataTransfer.files; 
 if (!files.length) return; 
 this.picValue = files[0]; 
 this.imgPreview(this.picValue); 
 }, 
 imgPreview (file) { 
 let self = this; 
 let Orientation; 
 //去获取拍照时的信息,解决拍出来的照片旋转问题 
 Exif.getData(file, function(){ 
  Orientation = Exif.getTag(this, 'Orientation'); 
 }); 
 // 看支持不支持FileReader 
 if (!file || !window.FileReader) return; 
 if (/^image/.test(file.type)) { 
  // 创建一个reader 
  let reader = new FileReader(); 
  // 将图片2将转成 base64 格式 
  reader.readAsDataURL(file); 
  // 读取成功后的回调 
  reader.onloadend = async function () { 
  let result = this.result; 
  let img = new Image(); 
  img.src = result; 
  //判断图片是否大于100K,是就直接上传,反之压缩图片 
  if (this.result.length <= (100 * 1024)) { 
  self.headerImage = this.result; 
  self.postImg(); 
  }else { 
  img.onload = function () { 
  let data = self.compress(img,Orientation); 
  self.headerImage = data; 
  self.postImg(); 
  } 
  } 
  } 
 } 
 }, 
 postImg () { 
 //这里写接口 
 }, 
 rotateImg (img, direction,canvas) { 
 //最小与最大旋转方向,图片旋转4次后回到原方向 
 const min_step = 0; 
 const max_step = 3; 
 if (img == null)return; 
 //img的高度和宽度不能在img元素隐藏后获取,否则会出错 
 let height = img.height; 
 let width = img.width; 
 let step = 2; 
 if (step == null) { 
  step = min_step; 
 } 
 if (direction == 'right') { 
  step++; 
  //旋转到原位置,即超过最大值 
  step > max_step && (step = min_step); 
 } else { 
  step--; 
  step < min_step && (step = max_step); 
 } 
 //旋转角度以弧度值为参数 
 let degree = step * 90 * Math.PI / 180; 
 let ctx = canvas.getContext('2d'); 
 switch (step) { 
  case 0: 
  canvas.width = width; 
  canvas.height = height; 
  ctx.drawImage(img, 0, 0); 
  break; 
  case 1: 
  canvas.width = height; 
  canvas.height = width; 
  ctx.rotate(degree); 
  ctx.drawImage(img, 0, -height); 
  break; 
  case 2: 
  canvas.width = width; 
  canvas.height = height; 
  ctx.rotate(degree); 
  ctx.drawImage(img, -width, -height); 
  break; 
  case 3: 
  canvas.width = height; 
  canvas.height = width; 
  ctx.rotate(degree); 
  ctx.drawImage(img, -width, 0); 
  break; 
 } 
 }, 
 compress(img,Orientation) { 
 let canvas = document.createElement("canvas"); 
 let ctx = canvas.getContext('2d'); 
 //瓦片canvas 
 let tCanvas = document.createElement("canvas"); 
 let tctx = tCanvas.getContext("2d"); 
 let initSize = img.src.length; 
 let width = img.width; 
 let height = img.height; 
 //如果图片大于四百万像素,计算压缩比并将大小压至400万以下 
 let ratio; 
 if ((ratio = width * height / 4000000) > 1) { 
 console.log("大于400万像素") 
 ratio = Math.sqrt(ratio); 
 width /= ratio; 
 height /= ratio; 
 } else { 
 ratio = 1; 
 } 
 canvas.width = width; 
 canvas.height = height; 
 // 铺底色 
 ctx.fillStyle = "#fff"; 
 ctx.fillRect(0, 0, canvas.width, canvas.height); 
 //如果图片像素大于100万则使用瓦片绘制 
 let count; 
 if ((count = width * height / 1000000) > 1) { 
 console.log("超过100W像素"); 
 count = ~~(Math.sqrt(count) + 1); //计算要分成多少块瓦片 
 //  计算每块瓦片的宽和高 
 let nw = ~~(width / count); 
 let nh = ~~(height / count); 
 tCanvas.width = nw; 
 tCanvas.height = nh; 
 for (let i = 0; i < count; i++) { 
  for (let j = 0; j < count; j++) { 
  tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh); 
  ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh); 
  } 
 } 
 } else { 
 ctx.drawImage(img, 0, 0, width, height); 
 } 
 //修复ios上传图片的时候 被旋转的问题 
 if(Orientation != "" && Orientation != 1){ 
 switch(Orientation){ 
  case 6://需要顺时针(向左)90度旋转 
  this.rotateImg(img,'left',canvas); 
  break; 
  case 8://需要逆时针(向右)90度旋转 
  this.rotateImg(img,'right',canvas); 
  break; 
  case 3://需要180度旋转 
  this.rotateImg(img,'right',canvas);//转两次 
  this.rotateImg(img,'right',canvas); 
  break; 
 } 
 } 
 //进行最小压缩 
 let ndata = canvas.toDataURL('image/jpeg', 0.1); 
 console.log('压缩前:' + initSize); 
 console.log('压缩后:' + ndata.length); 
 console.log('压缩率:' + ~~(100 * (initSize - ndata.length) / initSize) + "%"); 
 tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0; 
 return ndata; 
 }, 
 } 
} 
</script> 
<style> 
*{ 
 margin: 0; 
 padding: 0; 
} 
.show { 
 width: 100px; 
 height: 100px; 
 overflow: hidden; 
 position: relative; 
 border-radius: 50%; 
 border: 1px solid #d5d5d5; 
} 
.picture { 
 width: 100%; 
 height: 100%; 
 overflow: hidden; 
 background-position: center center; 
 background-repeat: no-repeat; 
 background-size: cover; 
} 
</style>

以上所述是小编给大家介绍的vue2实现移动端上传、预览、压缩图片解决拍照旋转问题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
javascript 字符串连接的性能问题(多浏览器)
Nov 18 Javascript
JQuery 选择和过滤方法代码总结
Nov 19 Javascript
jquery 插件开发 extjs中的extend用法小结
Jan 04 Javascript
jQuery弹出层始终垂直居中相对于屏幕或当前窗口
Apr 01 Javascript
Bootstrap打造一个左侧折叠菜单的系统模板(二)
May 17 Javascript
Bootstrap CSS布局之表格
Dec 17 Javascript
AngularJS的依赖注入实例分析(使用module和injector)
Jan 19 Javascript
three.js中文文档学习之创建场景
Nov 20 Javascript
vue树形结构获取键值的方法示例
Jun 21 Javascript
Vue实现远程获取路由与页面刷新导致404错误的解决
Jan 31 Javascript
es6数据变更同步到视图层的方法
Mar 04 Javascript
jquery实现直播弹幕效果
Nov 28 jQuery
Vue组件tree实现树形菜单
Apr 13 #Javascript
从零开始学习Node.js系列教程五:服务器监听方法示例
Apr 13 #Javascript
Angularjs 动态添加指令并绑定事件的方法
Apr 13 #Javascript
从零开始学习Node.js系列教程四:多页面实现数学运算的client端和server端示例
Apr 13 #Javascript
JS传参及动态修改页面布局
Apr 13 #Javascript
从零开始学习Node.js系列教程之基于connect和express框架的多页面实现数学运算示例
Apr 13 #Javascript
MUI 解决动态列表页图片懒加载再次加载不成功的bug问题
Apr 13 #Javascript
You might like
CodeIgniter针对lighttpd服务器URL重写的方法
2015/06/10 PHP
php版微信公众号接口实现发红包的方法
2016/10/14 PHP
phalcon model在插入或更新时会自动验证非空字段的解决办法
2016/12/29 PHP
PHP实现微信支付(jsapi支付)流程步骤详解
2018/03/15 PHP
Laravel框架模型的创建及模型对数据操作示例
2019/05/07 PHP
Javascript跨域请求的4种解决方式
2013/03/17 Javascript
javascript实现div浮动在网页最顶上并带关闭按钮效果实例
2013/08/13 Javascript
浅谈Javascript变量作用域问题
2014/12/16 Javascript
通过Tabs方法基于easyUI+bootstrap制作工作站
2016/03/28 Javascript
jquery分隔Url的param方法(推荐)
2016/05/25 Javascript
jquery获取复选框checkbox的值实现方法
2016/05/30 Javascript
jQuery 更改checkbox的状态,无效的解决方法
2016/07/22 Javascript
jquery 判断selection range 是否在容器中的简单实例
2016/08/02 Javascript
javascript 动态脚本添加的简单方法
2016/10/11 Javascript
angular ngClick阻止冒泡使用默认行为的方法
2016/11/03 Javascript
vue2笔记 — vue-router路由懒加载的实现
2017/03/03 Javascript
react-router JS 控制路由跳转实例
2017/06/15 Javascript
使用yeoman构建angular应用的方法
2017/08/14 Javascript
React-router4路由监听的实现
2018/08/07 Javascript
vuejs选中当前样式active的实例
2018/08/22 Javascript
详细分析React 表单与事件
2020/07/08 Javascript
[01:30]2016国际邀请赛中国区预选赛神秘商店火爆开启
2016/06/26 DOTA
Python使用win32 COM实现Excel的写入与保存功能示例
2018/05/03 Python
python分数表示方式和写法
2019/06/26 Python
解决pycharm最左侧Tool Buttons显示不全的问题
2019/12/17 Python
Python实现获取当前目录下文件名代码详解
2020/03/10 Python
python中对二维列表中一维列表的调用方法
2020/06/07 Python
浅谈pandas dataframe对除数是零的处理
2020/07/20 Python
Python接口自动化测试的实现
2020/08/28 Python
CSS3实现时间轴特效
2020/11/02 HTML / CSS
VELTRA台湾:世界自由行专家
2017/08/15 全球购物
雷蛇美国官网:Razer
2020/04/03 全球购物
应届生幼儿园求职信
2013/11/12 职场文书
金融与证券专业求职信
2014/06/22 职场文书
python 自动刷新网页的两种方法
2021/04/20 Python
浅谈Redis跟MySQL的双写问题解决方案
2022/02/24 Redis