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 相关文章推荐
EasySlider 基于jQuery功能强大简单易用的滑动门插件
Jun 11 Javascript
javascript学习笔记(五) Array 数组类型介绍
Jun 19 Javascript
js中typeof的用法汇总
Dec 12 Javascript
jQuery的图片滑块焦点图插件整理推荐
Dec 07 Javascript
jquery实现仿Flash的横向滑动菜单效果代码
Sep 17 Javascript
JavaScript中用let语句声明作用域的用法讲解
May 20 Javascript
Node.js Sequelize如何实现数据库的读写分离
Oct 23 Javascript
微信小程序 request接口的封装实例代码
Apr 26 Javascript
Vue.js中轻松解决v-for执行出错的三个方案
Jun 09 Javascript
用vue封装插件并发布到npm的方法步骤
Oct 18 Javascript
解决VUE框架 导致绑定事件的阻止冒泡失效问题
Feb 24 Javascript
jQuery HTML获取内容和属性操作实例分析
May 20 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
PHP中路径问题的解决方案
2006/10/09 PHP
网友原创的PHP模板类代码
2008/09/07 PHP
ThinkPHP CURD方法之field方法详解
2014/06/18 PHP
PHP利用func_get_args和func_num_args函数实现函数重载实例
2014/11/12 PHP
PHP下SSL加密解密、验证、签名方法(很简单)
2020/06/28 PHP
PHP生成制作验证码的简单实例
2016/06/12 PHP
javascript 触发事件列表 比较不错
2009/09/03 Javascript
如何防止回车(enter)键提交表单
2014/05/11 Javascript
轻松创建nodejs服务器(3):代码模块化
2014/12/18 NodeJs
详解微信小程序——自定义圆形进度条
2016/12/29 Javascript
ajax图片上传,图片异步上传,更新实例
2016/12/30 Javascript
用ES6写全屏滚动插件的示例代码
2018/05/02 Javascript
详解VUE中常用的几种import(模块、文件)引入方式
2018/07/03 Javascript
利用JavaScript缓存远程窃取Wi-Fi密码的思路详解
2018/11/05 Javascript
微信小程序环境下将文件上传到OSS的方法步骤
2019/05/31 Javascript
微信小程序接入腾讯云验证码的方法步骤
2020/01/07 Javascript
[01:32]TI珍贵瞬间系列(一)
2020/08/26 DOTA
Python import与from import使用及区别介绍
2018/09/06 Python
使用 Python 玩转 GitHub 的贡献板(推荐)
2019/04/04 Python
Python使用统计函数绘制简单图形实例代码
2019/05/15 Python
python脚本开机自启的实现方法
2019/06/28 Python
python kafka 多线程消费者&amp;手动提交实例
2019/12/21 Python
python实现在线翻译
2020/06/18 Python
Python二元算术运算常用方法解析
2020/09/15 Python
通过HTML5规范搞定i、em、b、strong元素的区别
2017/03/04 HTML / CSS
Gina Bacconi官网:吉娜贝康尼连衣裙和礼服
2018/04/24 全球购物
长安大学毕业生自我鉴定
2014/01/17 职场文书
电脑饰品店的创业计划书
2014/01/21 职场文书
职工运动会邀请函
2014/02/02 职场文书
商场消防演习方案
2014/02/12 职场文书
土木工程师职业规划范文
2014/03/07 职场文书
护理专业学生职业生涯规划范文
2014/03/11 职场文书
2014年加油站站长工作总结
2014/12/23 职场文书
交通安全温馨提示语
2015/07/14 职场文书
Nginx禁止ip访问或非法域名访问
2022/04/07 Servers
为什么MySQL8新特性会修改自增主键属性
2022/04/18 MySQL