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 相关文章推荐
基于jQuery的Spin Button自定义文本框数值自增或自减
Jul 17 Javascript
JS实现重新加载当前页面
Nov 29 Javascript
网站申请不到支付宝接口、微信接口,免接口收款实现方式几种解决办法
Dec 14 Javascript
jQuery Form插件使用详解_动力节点Java学院整理
Jul 17 jQuery
js封装成插件_Canvas统计图插件编写实例
Sep 12 Javascript
js中let和var定义变量的区别
Feb 08 Javascript
在Vue组件上动态添加和删除属性方法
Feb 23 Javascript
r.js来合并压缩css文件的示例
Apr 26 Javascript
Vue.js单向绑定和双向绑定实例分析
Aug 14 Javascript
微信小程序实现同一页面取值的方法分析
Apr 30 Javascript
小程序实现搜索框功能
Mar 26 Javascript
Vue 中使用 typescript的方法详解
Feb 17 Javascript
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
UTF-8正则表达式如何匹配汉字
2015/08/03 PHP
建议大家看下JavaScript重要知识更新
2007/07/08 Javascript
jQuery手机拨号界面特效代码分享
2015/08/27 Javascript
深入浅析JavaScript中的作用域和上下文
2016/03/26 Javascript
JS组件Bootstrap ContextMenu右键菜单使用方法
2016/04/17 Javascript
第七章之菜单按钮图标组件
2016/04/25 Javascript
基于JS实现的笛卡尔乘积之商品发布
2016/05/13 Javascript
深入理解JS DOM事件机制
2016/08/06 Javascript
ajax图片上传,图片异步上传,更新实例
2016/12/30 Javascript
jQuery实现QQ空间汉字转拼音功能示例
2017/07/10 jQuery
vue.js内部自定义指令与全局自定义指令的实现详解(利用directive)
2017/07/11 Javascript
基于JavaScript实现前端数据多条件筛选功能
2020/08/19 Javascript
Angular使用过滤器uppercase/lowercase实现字母大小写转换功能示例
2018/03/27 Javascript
webpack分离css单独打包的方法
2018/06/12 Javascript
基于vue2.0实现仿百度前端分页效果附实现代码
2018/10/30 Javascript
使用easyui从servlet传递json数据到前端页面的两种方法
2019/09/05 Javascript
javascript实现简易的计算器
2020/01/17 Javascript
design vue 表格开启列排序的操作
2020/10/28 Javascript
python为tornado添加recaptcha验证码功能
2014/02/26 Python
python实现通过代理服务器访问远程url的方法
2015/04/29 Python
Python中标准模块importlib详解
2017/04/16 Python
Python中的浮点数原理与运算分析
2017/10/12 Python
python实现百万答题自动百度搜索答案
2018/01/16 Python
python opencv实现图片旋转矩形分割
2018/07/26 Python
python实现代码统计器
2019/09/19 Python
手机使用python操作图片文件(pydroid3)过程详解
2019/09/25 Python
CSS3弹性盒模型flex box快速入门心得(必看篇)
2016/05/24 HTML / CSS
html特殊符号示例 html特殊字符编码对照表
2014/01/14 HTML / CSS
First Aid Beauty官网:FAB急救面霜
2018/05/24 全球购物
销售员个人求职的自我评价
2014/02/10 职场文书
教师通用专业自荐书范文
2014/02/11 职场文书
临床医学专业求职信
2014/08/08 职场文书
诚信承诺书
2015/01/19 职场文书
社区服务活动报告
2015/02/05 职场文书
Android Flutter实现3D动画效果示例详解
2022/04/07 Java/Android
MySQL去除密码登录告警的方法
2022/04/20 MySQL