中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

web前端圖片壓縮、方向糾正、預覽、上傳插件的方法是什么

發布時間:2021-11-06 16:22:11 來源:億速云 閱讀:140 作者:iii 欄目:web開發

這篇文章主要講解了“web前端圖片壓縮、方向糾正、預覽、上傳插件的方法是什么”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“web前端圖片壓縮、方向糾正、預覽、上傳插件的方法是什么”吧!

實現原理

壓縮圖片并且上傳主要用到filereader、canvas 以及 formdata 這三個h6的api和插件EXIF.js。邏輯并不難。整個過程就是:

(1)用戶使用input file上傳圖片的時候,用filereader讀取用戶上傳的圖片數據(base64格式)
??(2)把圖片數據傳入img對象,然后將img繪制到canvas上,用EXIF.js對圖片方向進行糾正,再調用canvas.toDataURL對圖片進行壓縮,獲取到壓縮后的base64格式圖片數據,轉成二進制
??(3)獲取到壓縮后的圖片二進制數據,預覽。
??(4)將壓縮后的圖片二進制數據塞入formdata,再通過XmlHttpRequest提交formdata

如此四步,就完成了圖片的壓縮、方向糾正、預覽和上傳。

插件設計思考

考慮到在實際項目中,可能用不同的開發框架(vue.js/JQ/react.js/angular.js/anu.js等),圖片預覽的UI樣式也可能不同,圖片數據上傳方法可能不同。因為圖片壓縮和方向糾正這兩塊的邏輯多變性比較低,我們這里把圖片壓縮和方向糾正抽離出來,封裝為一個插件庫。

【一】獲取圖片數據

先是獲取圖片數據,也就是監聽input file的change事件,然后獲取到用來壓縮上傳的文件對象files,將files傳到【圖片壓縮、方向糾正插件】中進行處理。

這時候根據每個人的需求,也可以預覽未壓縮的圖片。

//監聽上傳組件input的onchange事件,壓縮圖片,糾正圖片方向,同時獲取壓縮后的圖片
filechooser.onchange = function () {
    var fileList = this.files;
    
    //預覽壓縮前的圖片
    var files = Array.prototype.slice.call(fileList);
    files.forEach(function (file, i) {
        var reader = new FileReader();
        reader.onload = function () {
            var li = document.createElement("li")
            li.style.backgroundImage = 'url('+this.result+')';
            document.querySelector('.img_list').appendChild(li)
        }
        reader.readAsDataURL(file);
    });
    //處理圖片列表,getCompressiveFileList接受處理后的圖片數據列表
    //下面兩行代碼為圖片壓縮、方向糾正插件的用法,具體實現細節請繼續往下閱讀 ~_~ ↓↓↓
    var process = window.lzImgProcess();
    process(fileList, getCompressiveFileList);
}

【二】圖片壓縮、方向糾正插件實現

上面做完圖片數據的獲取后,就可以做process壓縮圖片的方法了。而壓縮圖片也并不是直接把圖片繪制到canvas再調用一下toDataURL就行的。

在IOS中,canvas繪制圖片是有兩個限制的:

首先是圖片的大小,如果圖片的大小超過兩百萬像素,圖片也是無法繪制到canvas上的,調用drawImage的時候不會報錯,但是你用toDataURL獲取圖片數據的時候獲取到的是空的圖片數據。

再者就是canvas的大小有限制,如果canvas的大小大于大概五百萬像素(即寬高乘積)的時候,不僅圖片畫不出來,其他什么東西也都是畫不出來的。

應對上面兩種限制,我把圖片寬度、高度壓縮控制在1000px以內,這樣圖片最大就不超過兩百萬像素了。在前端開發中,1000px*1000px基本可以滿足絕大部分的需求了。當然了還有更完美的瓦片式繪制的方法,我們這里就說瓦片式繪制方法了。

如此一來就解決了IOS上的兩種限制了。

除了上面所述的限制,還有兩個坑,一個就是canvas的toDataURL是只能壓縮jpg的(這句話的詳細解釋可以看下面的Tip講解),當用戶上傳的圖片是png的話,就需要轉成jpg,也就是統一用canvas.toDataURL('image/jpeg', 0.5) , 類型統一設成jpeg,而壓縮比就自己控制了。

另一個就是如果是png轉jpg,繪制到canvas上的時候,canvas存在透明區域的話,當轉成jpg的時候透明區域會變成黑色,因為canvas的透明像素默認為rgba(0,0,0,0),所以轉成jpg就變成rgba(0,0,0,1)了,也就是透明背景會變成了黑色。解決辦法就是繪制之前在canvas上鋪一層白色的底色。

在壓縮圖片之前,我們判斷圖片角度,如果圖片角度不正確,還需要用EXIF.js把圖片角度糾正過來。

壓縮完圖片,把base64的圖片數據轉成二進制數據存儲到暫存區中,等待被getBlobList獲取使用。

Tip: canvas的toDataURL是只能壓縮jpg這句話我可能說的不清楚,我想表達的意思是這個api無論是jpeg還是png,最后導出的時候,都跟jpeg沒啥差別了。因為png圖片的透明性質在canvas中是無效的,會被canvas添加默認的黑色背景,我在文中講解的時候,用白色背景處理了,所以最后導出的圖片,無論你設置的是png還是jpeg都跟jpeg沒啥區別了,因為無法保持png的透明度性質了

(function(window) {
    /**
     * 
     * 作者:混沌傳奇
     * 
     * 郵箱地址:iot-pro_lizeng@foxmail.com
     * 
     * 日期:2017-10-26
     * 
     * 插件功能:壓縮圖片&&糾正圖片方向&&返回二進制(Blob)圖片元數據組成的列表
     * 
     */
    window.lzImgProcess = function () {
        var Orientation = '', //圖片方向角
            blobList = [], //壓縮后的二進制圖片數據列表
            canvas = document.createElement("canvas"), //用于壓縮圖片(糾正圖片方向)的canvas
            ctx = canvas.getContext('2d'),
            file_type = 'image/jpeg', //圖片類型
            qlty = 0.5, //圖片壓縮品質,默認是0.5,可選范圍是0-1的數字類型的值,可配置
            imgWH = 1000; //壓縮后的圖片的最大寬度和高度,默認是1000px,可配置
        /**
         * @actionName process, 
         *        方法功能:壓縮圖片&&糾正圖片方向&&返回二進制(Blob)圖片元數據
         * 
         * @param fileList,傳入函數的文件列表對象,fileList對象是來自用戶在一個<input>元素上選擇文件后返回的FileList對象
         *        注意:圖片類型必須是jpeg||png
         *        比如:<input id="uploadImage" onchange="loadImageFile();" /> 
         *              function loadImageFile() {
         *                //獲取返回的fileList對象
         *                var fileList = document.getElementById("uploadImage").files;
         *              }
         * @param getBlobList [Blob],獲取壓縮結果的鉤子函數,接受一個參數。
         *        功能:在圖片壓縮完畢后,獲取壓縮后的二進制圖片數據對象組成的數組,參數即:壓縮后的二進制圖片數據(blob)組成的list
         *        
         * @param quality,傳入函數的圖片壓縮比率(品質),可選范圍0-1的數字類型的值,默認是0.5
         *
         * @param WH,傳入函數的圖片壓縮后的最大圖片寬度和高度,默認是1000,單位是px,可自由配置。
         *        注意:最好不要超過1000,數字過大,容易導致canvas壓縮失敗。由于沒做瓦片處理,所以有這個限制。1000*1000的圖片在前端中,基本也夠用了。
         *        
         */
        function process (fileList, getBlobList, quality, WH) {
            blobList = []; //初始化blobList
            // 判斷參數fileList的長度是否大于0
            if (!fileList.length){
                console.log('警告:傳進方法process的參數fileList長度必須大于零!!!')
                return;
            }
            //如果quality參數有值,則把quality賦值給qlty(圖片壓縮的品質)
            if(quality)
                qlty = quality;
            //如果WH參數有值,則把WH賦值給imgWH(壓縮后的圖片的最大寬度和高度)
            if(WH&&WH<1000&&WH>0){
                imgWH = WH;
            }
            // 把傳進來的fileList轉為數組類型
            var files = Array.prototype.slice.call(fileList);
            
            files.forEach(function (file, i) {
                if (!/\/(?:jpeg|png)/i.test(file.type)){
                    console.log('警告:圖片必須是jpeg||png類型!!!');
                    return;
                }
                // file_type = file.type;
                
                var reader = new FileReader();
                // 獲取圖片壓縮前大小,打印圖片壓縮前大小
                var size = file.size/1024 > 1024 ? (~~(10*file.size/1024/1024))/10 + "MB" :  ~~(file.size/1024) + "KB";
                // console.log('size:', size)
                reader.onload = function () {
                    var img = new Image();
                    img.src = this.result;
                    // 圖片加載完畢之后進行壓縮
                    if (img.complete) {
                        callback();
                    } else {
                        img.onload = callback;
                    }
                    function callback() {
                        //獲取照片方向角屬性,用戶旋轉控制  
                        EXIF.getData(img, function() {
                            // alert(EXIF.pretty(this));
                            EXIF.getAllTags(this);   
                            // alert(EXIF.getTag(this, 'Orientation'));
                            Orientation = EXIF.getTag(this, 'Orientation'); 
                            console.log('Orientation:', Orientation)
                            if(Orientation == ""||Orientation == undefined||Orientation == null){
                                Orientation = 1;
                            }
                        });
                        //獲取壓縮后的圖片二進制數據
                        var data = GetImgCompress(img);
                        //將二進制數據塞入到二進制數據列表中
                        blobList.push(data);
                        //將壓縮后的二進制圖片數據對象(blob)組成的list通過鉤子函數返回出去
                        if(blobList.length===files.length){
                            if(getBlobList)
                                getBlobList(blobList);
                        }
                        
                        img = null;
                    }
                };
                reader.readAsDataURL(file);
            })
        }
        /**
         * @actionName GetImgCompress,
         *     功能:判斷上傳圖片的方向,如果不是正確的,進行修正,并對圖片進行壓縮,壓縮完后,返回壓縮后的二進制圖片數據
         *     
         * @param img, 用來壓縮的圖片對象
         * 
         * @returns 返回的壓縮后的二進制圖片數據
         */
        function GetImgCompress(img){
            //如果方向角不為1,都需要進行旋轉
            if(Orientation != 1){
                switch(Orientation){
                    case 6://需要順時針90度旋轉
                        rotateImg(img,'right',canvas);
                        break;
                    case 8://需要逆時針90度旋轉
                        rotateImg(img,'left',canvas);
                        break;
                    case 3://需要180度旋轉
                        rotateImg(img,'right2',canvas);//轉兩次
                        break;
                }
            }else{
                //不做旋轉
                rotateImg(img,'no',canvas);
            }
            var ndata;
            
            ndata = canvas.toDataURL(file_type, qlty);
            
            //打印壓縮前后的大小,以及壓縮比率
            // var initSize = img.src.length;
            // console.log('壓縮前:' + initSize);
            // console.log('壓縮后:' + ndata.length, 'base64數據', ndata);
            // console.log('壓縮率:' + ~~(100 * (initSize - ndata.length) / initSize) + "%");
            //將壓縮后的base64數據轉為二進制數據
            ndata = dataURItoBlob(ndata);
            //清除canvas畫布的寬高
            canvas.width = canvas.height = 0;
            
            return ndata;
        }
        /**
         * @actionName rotateImg,
         *     功能:對圖片旋轉處理
         *     
         * @param img, 用來矯正方向的圖片對象
         * 
         * @param direction, 旋轉方向
         *
         * @param canvas, 用來繪制圖片的cavas畫布對象
         */
        function rotateImg(img, direction,canvas) {    
            
            //最小與最大旋轉方向,圖片旋轉4次后回到原方向    
            var min_step = 0;
            var max_step = 3;
            if (img == null)return;    
            //img的高度和寬度不能在img元素隱藏后獲取,否則會出錯    
            var height = img.height;    
            var width = img.width;
            if(width>imgWH || height>imgWH){
                var ratio = ~~(height/width*10)/10;
                if(width>height){
                    width = imgWH;
                    height = imgWH*ratio;
                }else{
                    height = imgWH;
                    width = height/ratio;
                }
                img.width = width;
                img.height = height;
            }
            var step = 2;    
            if (step == null) {    
                step = min_step;    
            }
            if (direction == 'no'){
                step = 0;    
            } else if (direction == 'left') {    
                step++;    
                //旋轉到原位置,即超過最大值    
                step > max_step && (step = min_step);    
            } else if (direction == 'right') {          
                step--;    
                step < min_step && (step = max_step);    
            } else {    
                //旋轉180度
            }
            //旋轉角度以弧度值為參數    
            var degree = step * 90 * Math.PI / 180; 
            switch (step) {
                case 0:
                    canvas.width = width;    
                    canvas.height = height;   
                    // 鋪底色
                    ctx.fillStyle = "#fff";
                    ctx.fillRect(0, 0, width, height);
                    ctx.drawImage(img, 0, 0, width, height);   
                    break;    
                case 1:
                    canvas.width = height;    
                    canvas.height = width;   
                    // 鋪底色
                    ctx.fillStyle = "#fff";
                    ctx.fillRect(0, 0, height, width);
                    ctx.rotate(degree);    
                    ctx.drawImage(img, 0, -height, width, height);    
                    break;
                case 2:
                    canvas.width = width;    
                    canvas.height = height;   
                    // 鋪底色
                    ctx.fillStyle = "#fff";
                    ctx.fillRect(0, 0, width, height);
                    ctx.rotate(degree);    
                    ctx.drawImage(img, -width, -height, width, height);    
                    break;    
                case 3:
                    canvas.width = height;    
                    canvas.height = width;   
                    // 鋪底色
                    ctx.fillStyle = "#fff";
                    ctx.fillRect(0, 0, height, width);
                    ctx.rotate(degree);    
                    ctx.drawImage(img, -width, 0, width, height);    
                    break;
            }
        }
        /**
         * dataURL to blob, ref to https://gist.github.com/fupslot/5015897
         * @param dataURI,圖片的base64格式數據
         * @returns {Blob}
         */
        function dataURItoBlob(dataURI) {
            var byteString = atob(dataURI.split(',')[1]);
            var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
            var ab = new ArrayBuffer(byteString.length);
            var ia = new Uint8Array(ab);
            for (var i = 0; i < byteString.length; i++) {
                ia[i] = byteString.charCodeAt(i);
            }
            return new Blob([ab], {type: mimeString});
        }
        /**
         * 返回一個process方法
         * 
         * process方法:用來壓縮圖片數據,在壓縮圖片的同時,默認會調用correctOrientation方法糾正圖片方向。
         * 
         */
        return process;
    }
})(window)

Exif.js 提供了 JavaScript 讀取圖像的原始數據的功能擴展,例如:拍照方向、相機設備型號、拍攝時間、ISO 感光度、GPS 地理位置等數據。
Exif.js官方github 倉庫地址: github.com/exif-js/exi…

【三】獲取壓縮后的圖片二進制數據,預覽圖片

完成圖片壓縮后,就可以獲取壓縮后的圖片二進制數據了,把獲取到的圖片二進制數據存起來;獲取到數據后,可以拿來預覽。

由于實際項目中,每個項目的UI樣式設計可能不一樣,開發者可以根據自己的UI樣式來預覽圖片。

//獲取壓縮后的圖片
function getCompressiveFileList(fileList) {
    blobFileList = fileList;
    // console.log('fileBlobList:', fileList);
    fileList.forEach(function (blob) {
        var reader = new FileReader();
        reader.onload = function () {
            var li = document.createElement("LI")
            li.style.backgroundImage = 'url('+this.result+')';
            document.querySelector('.imgCompress_list').appendChild(li)
        }
        reader.readAsDataURL(blob);
    })
}

【四】提交圖片數據到后臺

new一個formdata對象,將上一步獲取到的 blobFileList 圖片二進制數據 append 到 formdata中,用任意你喜歡的ajax庫進行上傳。當然也可以用原生ajax上傳。

//將壓縮后的二進制圖片數據流append到formdata對象中上傳到后臺服務器
//注意:上傳的是formdata對象,后臺接口接收的時候,也要從formdata對象中讀取二進制數據流
function formUpData(blobFiles){
    var formData = new FormData();
    formData.append("files", blobFiles);
    
    var xhr = new XMLHttpRequest();
    
    //鏈接你自己上傳圖片接口即可,這里的接口地址,是我寫的示例,不可真實使用,講解意義更大
    xhr.open('post', 'http://xxx/welcome/index/');
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4 && xhr.status == 200) {
                console.log('上傳成功!');
        }
    };
    xhr.send(formData);
}

感謝各位的閱讀,以上就是“web前端圖片壓縮、方向糾正、預覽、上傳插件的方法是什么”的內容了,經過本文的學習后,相信大家對web前端圖片壓縮、方向糾正、預覽、上傳插件的方法是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

web
AI

九江县| 长春市| 涿州市| 南郑县| 瑞安市| 宝山区| 木里| 景德镇市| 托克逊县| 荆州市| 枣强县| 阳信县| 中西区| 镇江市| 巩义市| 沁阳市| 吉木乃县| 福建省| 栖霞市| 永登县| 鲁甸县| 吉林省| 金寨县| 平江县| 岫岩| 江津市| 明溪县| 徐州市| 突泉县| 博乐市| 澳门| 富民县| 宁明县| 临高县| 安陆市| 鸡泽县| 巴塘县| 获嘉县| 桦川县| 通海县| 济源市|