浏览器图片压缩上传

需求

  客户端上传图片到服务器。大部分情况下,客户端的图片质量,远大于业务实际需要。上传,存储和下载展示,多出的都是浪费,节能环保,从源头做起。

实现原理 

  实现图片的压缩,实际上就是改变图片的尺寸(宽和高),或者改变图片的体积。使用CanvasRenderingContext2D.drawImage()HTMLCanvasElement.toDataURL()这两个API,就可以实现这两种操作。CanvasRenderingContext2D.drawImage() 可以将Image写入到canvas中,写入过程中可以自定义画布上绘制图像的宽度和高度,从而实现对图片尺寸的改变。HTMLCanvasElement.toDataURL()可以将canvas的内容,导出成图片,导出时可以指定图片的质量,从而改变图片的体积。
 
  但是我们从input得到的文件数据是File类型的,需要转变成CanvasRenderingContext2D.drawImage()能够写入的HTMLImageElement,HTMLCanvasElement.toDataURL()导出的数据格式是DataURL,而我们上传时需要Blob类型的数据,因此要实现得到文件,压缩,然后上传,我们需要对数据做一系列的处理。如同流水线加工,塞进去一只活蹦乱跳的大母鸡,最后得到一盒全家桶。

 

实现过程

  实现过程分为三个部分:

  1. 得到目标文件
  2. 压缩
  3. 上传

第一步:得到目标文件

 

        var input = document.getElementById('file');
        input.addEventListener('change',function(e){
            var file = this.files[0];
                fileName = file.name;
        });            

  

第二步:压缩

  压缩过程中,图片对应的数据类型在不断变化,按照类型变化,分为7个步骤

  1. File转化成Data URIs
  2. Data URIs转化成HTMLImageElement
  3. HTMLImageElement写入canvas
  4. canvas转化成DataURL
  5. DataURL转化成二进制String
  6. 二进制String转化成ArrayBuffer
  7. ArrayBuffer转化成Blob

1.File转化成Data URIs

       function fileToDataURL(file,callback) {
                var reader = new FileReader();
                reader.onload = function () {
                    var result = this.result;
                    callback(result);
                }

                reader.readAsDataURL(file);
            }

2.Data URIs转化成HTMLImageElement

 

       function dataURLToImage(dataURL,callback) {
                var img = new Image();
                img.onload = function() {
                    callback(img);
                }
                img.src = dataURL;
            }

 

3.HTMLImageElement写入canvas 

  创建canvas之后,可以设置canvas的宽和高。图片写入canvas的过程中,可以指定写入后的宽和高。这个过程,就是对图片尺寸进行更改。

4.canvas转化成DataURL

   这个过程中需要注意,canvas.toDataURL(type, encoderOptions); 当type为''image/jpeg''或者'image/webp'时,encoderOptions指定的图片质量系数才是有效的。

            function compress(img) {
                var canvas = document.createElement('canvas'),
                    width = img.width,
                    height = img.height;

                    canvas.width = width;
                    canvas.height = height;

                var context =  canvas.getContext('2d');
                context.drawImage(img, 0, 0, width, height);                

                var dataUrl = canvas.toDataURL('image/jpeg',0.7);

                return dataUrl;
            }

 

5.DataURL转化成二进制String

6.二进制String转化成ArrayBuffer

7.ArrayBuffer转化成Blob

 

            function dataUrlToBlob(dataUrl) {
                var text = window.atob(dataUrl.split(",")[1]);
                var buffer = new ArrayBuffer(text.length);
                var ubuffer = new Uint8Array(buffer);

                for (var i = 0; i < text.length; i++) {
                    ubuffer[i] = text.charCodeAt(i);
                }

                var blob;
                var type = 'image/jpeg';

                blob = new window.Blob([buffer], {type: type});

                return blob;
            }

 

 第三步:上传

   得到图片对应的Blob数据,使用FormData发送到服务端。

        function upload(blob,name) {
            
            var formData = new FormData();
            name = name.substring(0,name.lastIndexOf('.')) + '.jpeg';
            formData.append('file', blob ,name);
            formData.append('name',name);
            formData.append('size',blob.size);
            formData.append('type','image/jpeg');

            var xhr = new XMLHttpRequest();
            xhr.open('post','/fedemos/server/fileupload.php');
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    console.log()
                }
            }
            xhr.send(formData);
        }

 

代码示例

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
</head>
<body>
    <input id="file" type="file" name="file" >

    <script type="text/javascript">

        var input = document.getElementById('file');
        input.addEventListener('change',function(e){
            var file = this.files[0];
                fileName = file.name;

            imageCompress(file,function(blob){
                upload(blob,fileName);
            })
        });

        function imageCompress(file,callback) {

            fileToDataURL(file,function(dataURL){
                dataURLToImage(dataURL,function(img){
                    transform(img)
                })
            })

            function fileToDataURL(file,callback) {
                var reader = new FileReader();
                reader.onload = function () {
                    var result = this.result;
                    callback(result);
                }

                reader.readAsDataURL(file);
            }

            function dataURLToImage(dataURL,callback) {
                var img = new Image();
                img.onload = function() {
                    callback(img);
                }
                img.src = dataURL;
            }

            function transform(img) {
                var dataUrl = compress(img);
                var blob = dataUrlToBlob(dataUrl);

                callback(blob);
            }

            function compress(img) {
                var canvas = document.createElement('canvas'),
                    width = img.width,
                    height = img.height;

                    // if(width>1280 && width>height) {                        
                    //     height = height*1280/width;
                    //     width = 1280;
                    // } else if(height>width && height>1280) {
                        
                    //     width = width*1280/height;
                    //     height = 1280;
                    // }

                    canvas.width = width;
                    canvas.height = height;

                var context =  canvas.getContext('2d');
                context.drawImage(img, 0, 0, width, height);                

                var dataUrl = canvas.toDataURL('image/jpeg',0.7);

                return dataUrl;
            }

            function dataUrlToBlob(dataUrl) {
                var text = window.atob(dataUrl.split(",")[1]);
                var buffer = new ArrayBuffer(text.length);
                var ubuffer = new Uint8Array(buffer);

                for (var i = 0; i < text.length; i++) {
                    ubuffer[i] = text.charCodeAt(i);
                }

                var blob;
                var type = 'image/jpeg';

                blob = new window.Blob([buffer], {type: type});

                return blob;
            }
        }

        function upload(blob,name) {
            
            var formData = new FormData();
            name = name.substring(0,name.lastIndexOf('.')) + '.jpeg';
            formData.append('file', blob ,name);
            formData.append('name',name);
            formData.append('size',blob.size);
            formData.append('type','image/jpeg');

            var xhr = new XMLHttpRequest();
            xhr.open('post','/fedemos/server/fileupload.php');
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    console.log()
                }
            }
            xhr.send(formData);
        }
    </script>
</body>
</html>

 

参考

转载于:https://www.cnblogs.com/breezernyu/p/6419571.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值