zoukankan      html  css  js  c++  java
  • 利用canvas对上传图片进行上传前压缩

    利用谷歌调式工具发现,图片大小直接影响着首屏加载时间。

    且考虑到后期服务端压力,图片压缩特别必要。

    本文是前端利用canvas实现图片。参考文章:https://www.cnblogs.com/007sx/p/7583202.html

    本文将其改为插件形式,适合单文件压缩,多文件可以采用生成多个二进制文件的方法,然后一并上传。具体后面研究。

    说说原理,压缩涉及三个关键点:

    1,一个图片前端可被加载,基于file:协议的路径是不能产生onload事件,所以需要借助浏览器的接口将图片转为可加载文件,一种是通过FileReader,另一种是

    通过URL.createObjectURL。

    2,利用canvas,获取图片的高度和宽度之后,利用drawImage输出图片,再利用canvas的toDataURL输出base64的图片。

    3,将base64转为二进制文件。

    案例代码:

      1 <!DOCTYPE html>
      2 <html>
      3 
      4 <head>
      5     <meta charset="UTF-8">
      6     <title>XMLHttpRequest上传文件压缩上传图片文件</title>
      7 </head>
      8 
      9 <body>
     10     <input type="file" id="file" name="myfile" accept="image/x-png, image/jpg, image/jpeg, image/gif" />
     11     <input type="button" onclick="UpladFile()" value="上传" />
     12     <script type="text/javascript">
     13     (function() {
     14         function compress(opts, fileObj) {
     15             this.defaults = {
     16                 id: "#file",
     17                 quality: 0.4,
     18                 url: "",
     19                 callback: function(bl) {
     20                     console.log(bl);
     21                 }
     22             };
     23 
     24             if (typeof opts === "object") {
     25                 this.options = Object.assign({}, this.defaults, opts)
     26             } else {
     27                 this.options = this.defaults;
     28             }
     29             fileObj = fileObj || document.querySelector(this.options.id).files[0];
     30             this.init(fileObj);
     31         }
     32         compress.prototype = {
     33             version: "1.0.1",
     34             init: function(fileObj) {
     35                 _this = this;
     36                 //promise处理异步
     37                 this.photoCompress(fileObj).then(function(res) {
     38                     return _this.canvasDataUrl.call(_this, res);
     39                 }).catch(function(err) {
     40                     console.log(err);
     41                 }).then(function(res) {
     42                     var bl = _this.convertBase64UrlToBlob(res);
     43                     _this.options.callback(bl);
     44                 }).catch(function(err) {
     45                     console.log(err);
     46                 })
     47 
     48             },
     49             photoCompress: function(file) {
     50                 var ready = new FileReader();
     51                 ready.readAsDataURL(file);
     52                 return new Promise(function(resolve, reject) {
     53                     ready.onload = function() {
     54                         var re = this.result;
     55                         resolve(re);
     56                     }
     57                     ready.onerror = function(err) {
     58                         reject(err)
     59                     }
     60                 })
     61 
     62             },
     63             canvasDataUrl: function(res) {
     64 
     65                 var img = new Image();
     66                 img.src = res;
     67                 _this = this;
     68                 return new Promise(function(resolve, reject) {
     69                     img.onload = function() {
     70                         // 默认按比例压缩
     71                         var w = this.width,
     72                             h = this.height;
     73                         //生成canvas
     74                         var canvas = document.createElement('canvas');
     75                         var ctx = canvas.getContext('2d');
     76                         // 创建属性节点
     77                         var anw = document.createAttribute("width");
     78                         anw.nodeValue = w;
     79                         var anh = document.createAttribute("height");
     80                         anh.nodeValue = h;
     81                         canvas.setAttributeNode(anw);
     82                         canvas.setAttributeNode(anh);
     83                         ctx.drawImage(this, 0, 0, w, h);
     84 
     85                         // quality值越小,所绘制出的图像越模糊
     86                         var base64 = canvas.toDataURL('image/jpeg', _this.options.quality);
     87                         // 回调函数返回base64的值
     88                         resolve(base64)
     89                     }
     90                     img.onerror = function(err) {
     91                         reject(err)
     92                     }
     93                 })
     94             },
     95 
     96             //base64转为二进制数据,后端可直接利用
     97             convertBase64UrlToBlob: function(urlData) {
     98                 var arr = urlData.split(','),
     99                     mime = arr[0].match(/:(.*?);/)[1],
    100                     bstr = atob(arr[1]),
    101                     n = bstr.length,
    102                     u8arr = new Uint8Array(n);
    103                 while (n--) {
    104                     u8arr[n] = bstr.charCodeAt(n);
    105                 }
    106                 return new Blob([u8arr], { type: mime });
    107             }
    108         }
    109         window.compress = compress;
    110 
    111     })();
    112 
    113     //上传文件方法
    114     function UpladFile() {
    115 
    116         var url = "./upload"; // 接收上传文件的后台地址 
    117         new compress({
    118             quality: 0.4,
    119             url: url,
    120             callback: function(bl) {
    121                 var form = new FormData();
    122                 form.append("file", bl, "file_" + Date.parse(new Date()) + ".jpg"); // 文件对象
    123                 var xhr = new XMLHttpRequest();
    124                 xhr.open("post", url, true);
    125                 xhr.onreadystatechange = function(evt) {
    126                     if (xhr.readyState === 4 && xhr.status === 200) {
    127                          uploadComplete(evt);
    128                     }
    129                 }
    130 
    131                 xhr.send(form); //开始上传,发送form数据
    132             }
    133         })
    134     }
    135 
    136     //上传成功响应
    137     function uploadComplete(evt) {
    138         //服务断接收完文件返回的结果
    139         var data = JSON.parse(evt.target.responseText);
    140         if (data.success) {
    141             alert("上传成功!");
    142         } else {
    143             alert("上传失败!");
    144         }
    145 
    146     }
    147     </script>
    148 </body>
    149 
    150 </html>
    View Code

    后端采用thinkphp5,代码index控制器下,方法

     1    public function upload(){
     2        
     3          // 获取表单上传文件 例如上传了001.jpg
     4      $file = request()->file('file');
     5      $arr=array("code"=>1,"success"=>true);
     6      // 移动到框架应用根目录/public/uploads/ 目录下
     7      if($file){
     8         $info = $file->move(ROOT_PATH . 'public' . DS . 'uploads');
     9         if($info){
    10             
    11             echo json_encode($arr);
    12 
    13         }else{
    14 
    15           return "error";
    16             // 上传失败获取错误信息
    17             echo $file->getError();
    18         }
    19       };
    20     }

    多张图片上传前压缩

      1 <!DOCTYPE html>
      2 <html>
      3 
      4 <head>
      5     <meta charset="UTF-8">
      6     <title>XMLHttpRequest上传文件压缩上传图片文件多</title>
      7 </head>
      8 
      9 <body>
     10     <input type="file" id="files" name="myfile" multiple accept="image/x-png, image/jpg, image/jpeg, image/gif" />
     11     <input type="button" onclick="UpladFile()" value="上传" />
     12     <script type="text/javascript">
     13     /*
     14             三个参数
     15             file:一个是文件(类型是图片格式),
     16             w:一个是文件压缩的后宽度,宽度越小,字节越小
     17             objDiv:一个是容器或者回调函数
     18             photoCompress()
     19              */
     20     function photoCompress(file, w, objDiv) {
     21         var ready = new FileReader();
     22         /*开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容.*/
     23         ready.readAsDataURL(file);
     24         ready.onload = function() {
     25             var re = this.result;
     26             canvasDataURL(re, w, objDiv)
     27         }
     28     }
     29 
     30     function canvasDataURL(path, obj, callback) {
     31         var img = new Image();
     32         img.src = path;
     33         img.onload = function() {
     34             var that = this;
     35             // 默认按比例压缩
     36             var w = that.width,
     37                 h = that.height,
     38                 scale = w / h;
     39             w = obj.width || w;
     40             h = obj.height || (w / scale);
     41             var quality = 0.7; // 默认图片质量为0.7
     42             //生成canvas
     43             var canvas = document.createElement('canvas');
     44             var ctx = canvas.getContext('2d');
     45             // 创建属性节点
     46             var anw = document.createAttribute("width");
     47             anw.nodeValue = w;
     48             var anh = document.createAttribute("height");
     49             anh.nodeValue = h;
     50             canvas.setAttributeNode(anw);
     51             canvas.setAttributeNode(anh);
     52             ctx.drawImage(that, 0, 0, w, h);
     53             // 图像质量
     54             if (obj.quality && obj.quality <= 1 && obj.quality > 0) {
     55                 quality = obj.quality;
     56             }
     57             // quality值越小,所绘制出的图像越模糊
     58             var base64 = canvas.toDataURL('image/jpeg', quality);
     59             // 回调函数返回base64的值
     60             callback(base64);
     61         }
     62     }
     63     /**
     64      * 将以base64的图片url数据转换为Blob
     65      * @param urlData
     66      *            用url方式表示的base64图片数据
     67      */
     68     function convertBase64UrlToBlob(urlData) {
     69         var arr = urlData.split(','),
     70             mime = arr[0].match(/:(.*?);/)[1],
     71             bstr = atob(arr[1]),
     72             n = bstr.length,
     73             u8arr = new Uint8Array(n);
     74         while (n--) {
     75             u8arr[n] = bstr.charCodeAt(n);
     76         }
     77         return new Blob([u8arr], { type: mime });
     78     }
     79 
     80     //上传文件方法
     81     function UpladFile() {
     82 
     83         var url = "./upload"; // 接收上传文件的后台地址 
     84         var form = new FormData();
     85         var files = document.querySelector("#files").files;
     86         files = Array.prototype.slice.call(files);
     87         files.forEach(function(val, index) {
     88             photoCompress(val, {
     89                 quality: 0.2
     90             }, function(base64Codes) {
     91                 console.log(index);
     92                 //console.log("压缩后:" + base.length / 1024 + " " + base);
     93                 var bl = convertBase64UrlToBlob(base64Codes);
     94                 form.append("file" + index, bl, "file_" + Date.parse(new Date()) + ".jpg"); // 文件对象
     95                 if (index + 1 === files.length) {
     96                     xhr = new XMLHttpRequest(); // XMLHttpRequest 对象
     97                     xhr.open("post", url, true); //post方式,url为服务器请求地址,true 该参数规定请求是否异步处理。
     98                     xhr.onload = uploadComplete; //请求完成
     99                     xhr.send(form); //开始上传,发送form数据
    100                 }
    101             });
    102         })
    103     }
    104 
    105     //上传成功响应
    106     function uploadComplete(evt) {
    107         //服务断接收完文件返回的结果
    108         var data = JSON.parse(evt.target.responseText);
    109         if (data.success) {
    110             alert("上传成功!");
    111         } else {
    112             alert("上传失败!");
    113         }
    114 
    115     }
    116     </script>
    117 </body>
    118 
    119 </html>
    View Code
  • 相关阅读:
    Jenkins参数化构建
    python笔记
    jenkins定时任务
    技巧:Vimdiff 使用
    clover如何使用UEFI引导和EFI驱动选择
    Broadcast BCM94322 用ubuntu修改ID
    MAC实现睡眠和休眠唤醒
    MAC的睡眠模式介绍
    linux 用dd命令读写引导区文件
    MAC下打开FTP服务
  • 原文地址:https://www.cnblogs.com/zhensg123/p/9338662.html
Copyright © 2011-2022 走看看