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

来源:互联网 发布:linux属于应用软件吗 编辑:程序博客网 时间:2024/05/17 07:06

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

[html] view plain copy
  1. <template>  
  2.   <div>  
  3.     <div style="padding:20px;">  
  4.       <div class="show">  
  5.         <div class="picture" :style="'backgroundImage:url('+headerImage+')'"></div>  
  6.       </div>  
  7.       <div style="margin-top:20px;">  
  8.         <input type="file" id="upload" accept="image" @change="upload">  
  9.         <label for="upload"></label>  
  10.       </div>  
  11.     </div>  
  12.   </div>  
  13. </template>  
  14.   
  15. <script>  
  16. import Exif from 'exif-js'  
  17.   
  18. export default {  
  19.   data () {  
  20.     return {  
  21.       headerImage:'',picValue:''  
  22.     }  
  23.   },  
  24.   mounted () {  
  25.   },  
  26.   methods: {  
  27.     upload (e) {  
  28.       let files = e.target.files || e.dataTransfer.files;  
  29.       if (!files.length) return;  
  30.       this.picValue = files[0];  
  31.       this.imgPreview(this.picValue);  
  32.     },  
  33.     imgPreview (file) {  
  34.       let self = this;  
  35.       let Orientation;  
  36.       //去获取拍照时的信息,解决拍出来的照片旋转问题  
  37.       Exif.getData(file, function(){  
  38.           Orientation = Exif.getTag(this, 'Orientation');  
  39.       });  
  40.       // 看支持不支持FileReader  
  41.       if (!file || !window.FileReader) return;  
  42.   
  43.       if (/^image/.test(file.type)) {  
  44.           // 创建一个reader  
  45.           let reader = new FileReader();  
  46.           // 将图片2将转成 base64 格式  
  47.           reader.readAsDataURL(file);  
  48.           // 读取成功后的回调  
  49.           reader.onloadend = function () {  
  50.             let result = this.result;  
  51.             let img = new Image();  
  52.             img.src = result;  
  53.             //判断图片是否大于100K,是就直接上传,反之压缩图片  
  54.             if (this.result.length <= (100 * 1024)) {  
  55.               self.headerImage = this.result;  
  56.               self.postImg();  
  57.             }else {  
  58.               img.onload = function () {  
  59.                 let data = self.compress(img,Orientation);  
  60.                 self.headerImage = data;  
  61.                 self.postImg();  
  62.               }  
  63.             }  
  64.           }   
  65.         }  
  66.       },  
  67.       postImg () {  
  68.         //这里写接口  
  69.       },  
  70.       rotateImg (img, direction,canvas) {  
  71.         //最小与最大旋转方向,图片旋转4次后回到原方向      
  72.         const min_step = 0;      
  73.         const max_step = 3;        
  74.         if (img == null)return;      
  75.         //img的高度和宽度不能在img元素隐藏后获取,否则会出错      
  76.         let height = img.height;      
  77.         let width = img.width;        
  78.         let step = 2;      
  79.         if (step == null) {      
  80.             step = min_step;      
  81.         }      
  82.         if (direction == 'right') {      
  83.             step++;      
  84.             //旋转到原位置,即超过最大值      
  85.             step > max_step && (step = min_step);      
  86.         } else {      
  87.             step--;      
  88.             step < min_step && (step = max_step);      
  89.         }       
  90.         //旋转角度以弧度值为参数      
  91.         let degree = step * 90 * Math.PI / 180;      
  92.         let ctx = canvas.getContext('2d');      
  93.         switch (step) {      
  94.           case 0:      
  95.               canvas.width = width;      
  96.               canvas.height = height;      
  97.               ctx.drawImage(img, 0, 0);      
  98.               break;      
  99.           case 1:      
  100.               canvas.width = height;      
  101.               canvas.height = width;      
  102.               ctx.rotate(degree);      
  103.               ctx.drawImage(img, 0, -height);      
  104.               break;      
  105.           case 2:      
  106.               canvas.width = width;      
  107.               canvas.height = height;      
  108.               ctx.rotate(degree);      
  109.               ctx.drawImage(img, -width, -height);      
  110.               break;      
  111.           case 3:      
  112.               canvas.width = height;      
  113.               canvas.height = width;      
  114.               ctx.rotate(degree);      
  115.               ctx.drawImage(img, -width, 0);      
  116.               break;  
  117.         }      
  118.     },  
  119.     compress(img,Orientation) {  
  120.       let canvas = document.createElement("canvas");  
  121.       let ctx = canvas.getContext('2d');  
  122.         //瓦片canvas  
  123.       let tCanvas = document.createElement("canvas");  
  124.       let tctx = tCanvas.getContext("2d");  
  125.       let initSize = img.src.length;  
  126.       let width = img.width;  
  127.       let height = img.height;  
  128.       //如果图片大于四百万像素,计算压缩比并将大小压至400万以下  
  129.       let ratio;  
  130.       if ((ratio = width * height / 4000000) > 1) {  
  131.         console.log("大于400万像素")  
  132.         ratio = Math.sqrt(ratio);  
  133.         width /= ratio;  
  134.         height /= ratio;  
  135.       } else {  
  136.         ratio = 1;  
  137.       }  
  138.       canvas.width = width;  
  139.       canvas.height = height;  
  140.   //        铺底色  
  141.       ctx.fillStyle = "#fff";  
  142.       ctx.fillRect(0, 0, canvas.width, canvas.height);  
  143.       //如果图片像素大于100万则使用瓦片绘制  
  144.       let count;  
  145.       if ((count = width * height / 1000000) > 1) {  
  146.         console.log("超过100W像素");  
  147.         count = ~~(Math.sqrt(count) + 1); //计算要分成多少块瓦片  
  148.   //            计算每块瓦片的宽和高  
  149.         let nw = ~~(width / count);  
  150.         let nh = ~~(height / count);  
  151.         tCanvas.width = nw;  
  152.         tCanvas.height = nh;  
  153.         for (let i = 0; i < count; i++) {  
  154.           for (let j = 0; j < count; j++) {  
  155.             tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh);  
  156.             ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh);  
  157.           }  
  158.         }  
  159.       } else {  
  160.         ctx.drawImage(img, 0, 0, width, height);  
  161.       }  
  162.       //修复ios上传图片的时候 被旋转的问题  
  163.       if(Orientation != "" && Orientation != 1){  
  164.         switch(Orientation){  
  165.           case 6://需要顺时针(向左)90度旋转  
  166.               this.rotateImg(img,'left',canvas);  
  167.               break;  
  168.           case 8://需要逆时针(向右)90度旋转  
  169.               this.rotateImg(img,'right',canvas);  
  170.               break;  
  171.           case 3://需要180度旋转  
  172.               this.rotateImg(img,'right',canvas);//转两次  
  173.               this.rotateImg(img,'right',canvas);  
  174.               break;  
  175.         }  
  176.       }  
  177.       //进行最小压缩  
  178.       let ndata = canvas.toDataURL('image/jpeg', 0.1);  
  179.       console.log('压缩前:' + initSize);  
  180.       console.log('压缩后:' + ndata.length);  
  181.       console.log('压缩率:' + ~~(100 * (initSize - ndata.length) / initSize) + "%");  
  182.       tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;  
  183.       return ndata;  
  184.     },  
  185.   }  
  186. }  
  187. </script>  
  188.   
  189. <style>  
  190. *{  
  191.   margin: 0;  
  192.   padding: 0;  
  193. }  
  194. .show {  
  195.   width: 100px;  
  196.   height: 100px;  
  197.   overflow: hidden;  
  198.   position: relative;  
  199.   border-radius: 50%;  
  200.   border: 1px solid #d5d5d5;  
  201. }  
  202. .picture {  
  203.   width: 100%;  
  204.   height: 100%;  
  205.   overflow: hidden;  
  206.   background-position: center center;  
  207.   background-repeat: no-repeat;  
  208.   background-size: cover;   
  209. }  
  210. </style>  
原文链接:http://blog.csdn.net/xiaogezl/article/details/70156500





阅读全文
1 0
原创粉丝点击