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 相关文章推荐
自己开发Dojo的建议框架
Sep 24 Javascript
javascript 表单规则集合对象
Jul 21 Javascript
jquery ajax,ashx,json的用法总结
Feb 12 Javascript
显示今天的日期js代码(阳历和农历)
Sep 30 Javascript
浅谈jQuery中对象遍历.eq().first().last().slice()方法
Nov 26 Javascript
jQuery实现按键盘方向键翻页特效
Mar 18 Javascript
js实现图片点击左右轮播
Jul 08 Javascript
EasyUI创建对话框的两种方式
Aug 23 Javascript
jQuery实现的文字逐行向上间歇滚动效果示例
Sep 06 jQuery
Vue 配合eiement动态路由,权限验证的方法
Sep 26 Javascript
Angular value与ngValue区别详解
Nov 27 Javascript
Vue vee-validate插件的简单使用
Jun 22 Vue.js
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
星际RPG字典
2020/03/04 星际争霸
PHP下对字符串的递增运算代码
2010/08/21 PHP
php去掉字符串的最后一个字符附substr()的用法
2011/03/23 PHP
php关键字仅替换一次的实现函数
2015/10/29 PHP
JavaScript面向对象编程
2008/03/02 Javascript
用JavaScript页面不刷新时全选择,全删除(GridView)
2009/04/14 Javascript
jquery实现marquee效果(文字或者图片的水平垂直滚动)
2013/01/07 Javascript
js防止表单重复提交的两种方法
2013/09/30 Javascript
js中settimeout方法加参数
2014/02/28 Javascript
一个简单的jquery的多选下拉框(自写)
2014/05/05 Javascript
实例讲解JavaScript中的this指向错误解决方法
2016/06/13 Javascript
webpack常用配置项配置文件介绍
2016/11/07 Javascript
微信小程序 textarea 组件详解及简单实例
2017/01/10 Javascript
基于node打包可执行文件工具_Pkg使用心得分享
2018/01/24 Javascript
详解如何在vscode里面调试js和node.js的方法步骤
2018/12/24 Javascript
微信小程序template模版的使用方法
2019/04/13 Javascript
javascript数据类型中的一些小知识点(推荐)
2019/04/18 Javascript
vue微信分享插件使用方法详解
2020/02/18 Javascript
javascript单张多张图无缝滚动实例代码
2020/05/10 Javascript
python中的实例方法、静态方法、类方法、类变量和实例变量浅析
2014/04/26 Python
Flask框架Flask-Login用法分析
2018/07/23 Python
OpenCV+python手势识别框架和实例讲解
2018/08/03 Python
python实现计数排序与桶排序实例代码
2019/03/28 Python
详解python项目实战:模拟登陆CSDN
2019/04/04 Python
django Admin文档生成器使用详解
2019/07/22 Python
keras model.fit 解决validation_spilt=num 的问题
2020/06/19 Python
Python实现JS解密并爬取某音漫客网站
2020/10/23 Python
python中requests模拟登录的三种方式(携带cookie/session进行请求网站)
2020/11/17 Python
解决HTML5手机端页面缩放的问题
2017/10/27 HTML / CSS
往来会计岗位职责
2013/12/19 职场文书
小学生红领巾广播稿
2014/01/21 职场文书
歌颂党的演讲稿
2014/09/10 职场文书
2014年应急工作总结
2014/12/11 职场文书
国庆节主题班会
2015/08/15 职场文书
2016教师节问候语
2015/11/10 职场文书
python自动化之如何利用allure生成测试报告
2021/05/02 Python