瀏覽器圖片壓縮上傳


需求

  客戶端上傳圖片到服務器。大部分情況下,客戶端的圖片質量,遠大於業務實際需要。上傳,存儲和下載展示,多出的都是浪費,節能環保,從源頭做起。

實現原理 

  實現圖片的壓縮,實際上就是改變圖片的尺寸(寬和高),或者改變圖片的體積。使用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>

 

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM