前端圖片壓縮常見的一些解決辦法
問題產(chǎn)生背景
在某一h5的項目,要求上傳的圖片格式為 base64 , 問題是用戶上傳的圖片基本都在MB 級別,轉(zhuǎn)base64 以后,圖片的體積會增大30%以上,隨著圖片的體積增加,轉(zhuǎn)換的base64 格式文件體積越大,如果此時前端不對用戶上傳的圖片體積進行壓縮,可能會導(dǎo)致服務(wù)器壓力過大,從而崩潰;
解決辦法
1、使用純 js 解決
解決思路:
1、通過 input 文件選擇框拿到要上傳的圖片文件file
2、FileReader.readAsDataURL() 讀取 file 內(nèi)容。完成后 result 屬性中將包含一個 data: URL格式的 Base64字符串以表示所讀取文件的內(nèi)容。
3、創(chuàng)建一個 img 標(biāo)簽,將 FileReader 對象返回的 base64 格式 url 給到一個 img 標(biāo)簽
4、img.onload() 函數(shù)中獲取圖片的尺寸,再通過 canvas.drawImage() 繪制圖像,設(shè)置尺寸或者圖像的質(zhì)量等
canvas.toDataURL(file.type, quality) 設(shè)置圖像的質(zhì)量,將 canvas 轉(zhuǎn)換為圖片 base64 格式
代碼如下所示:
compressImg(file) { const reader = new FileReader(); // readAsDataURL 方法會讀取指定的 Blob 或 File 對象。讀取操作完成的時候,readyState 會變成已完成DONE,并觸發(fā) loadend (en-US) 事件, // 同時 result 屬性將包含一個data:URL格式的字符串(base64編碼)以表示所讀取文件的內(nèi)容。 reader.readAsDataURL(file); reader.onload = () => { const img = new Image(); img.src = reader.result; img.onload = () => { // 圖片的寬高 const w = img.width; const h = img.height; const canvas = document.createElement("canvas"); // canvas對圖片進行裁剪,這里設(shè)置為圖片的原始尺寸 canvas.width = w; canvas.height = h; const ctx = canvas.getContext("2d"); // canvas中,png轉(zhuǎn)jpg會變黑底,所以先給canvas鋪一張白底 ctx.fillStyle = "#fff"; // fillRect()方法繪制一個填充了內(nèi)容的矩形,這個矩形的開始點(左上點)在 // (x, y) ,它的寬度和高度分別由width 和 height 確定,填充樣式由當(dāng)前的fillStyle 決定。 ctx.fillRect(0, 0, canvas.width, canvas.height); // 繪制圖像 ctx.drawImage(img, 0, 0, w, h); // canvas轉(zhuǎn)圖片達到圖片壓縮效果 // 返回一個包含圖片展示的 data URI base64 在指定圖片格式為 image/jpeg 或 image/webp的情況下, // 可以從 0 到 1 的區(qū)間內(nèi)選擇圖片的質(zhì)量。如果超出取值范圍,將會使用默認(rèn)值 0.92。其他參數(shù)會被忽略。 const dataUrl = canvas.toDataURL("image/jpeg", 0.8); // base64格式文件轉(zhuǎn)成Blob文件格式 return blobFile = dataURLtoBlob(dataUrl); // 拿到這個blobFile文件就可以上傳給服務(wù)端 console.log("壓縮后的file----------", blobFile); }; }; } // canvas生成的格式為base64,如果需要Blob格式可按如下進行轉(zhuǎn)化 dataURLtoBlob(dataurl) { const arr = dataurl.split(","), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]); let n = bstr.length; const u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], { type: mime }); },
使用以上方法存在缺點:
- 壓縮后的格式只能是 jpeg 格式,如果需要其他格式的可能需要優(yōu)化或者用別的方法
2、插件 js-image-compressor
在使用中,我們可以根據(jù)自身需求自定義配置壓縮比(quality)、輸出圖片類型(mimeType)、寬(width)、高(height)、最大寬(maxWidth)、最大高(maxHeight)、最小寬(minWidth)、最大高(minHeight)、png轉(zhuǎn)jpeg閾值(convertSize)、是否矯正jpeg方向(redressOrientation)和是否寬松模式(loose)。
● 是否矯正jpeg方向(redressOrientation),jpeg 格式圖片在某些iOS瀏覽器會按其方向呈現(xiàn)圖像,這個選項可以控制恢復(fù)初始方向,默認(rèn)為 true;
● 是否寬松模式(loose)、的意思是控制當(dāng)壓縮的圖片 size 大于源圖片,輸出源圖片,否則輸出壓縮后圖片,默認(rèn)是 true。
以下是標(biāo)準(zhǔn)配置:
var options = { file: file, quality: 0.6, mimeType: 'image/jpeg', maxWidth: 2000, maxHeight: 2000, width: 1000, height: 1000, minWidth: 500, minHeight: 500, convertSize: Infinity, loose: true, redressOrientation: true, // 壓縮前回調(diào) beforeCompress: function (result) { console.log('壓縮之前圖片尺寸大小: ', result.size); console.log('mime 類型: ', result.type); }, // 壓縮成功回調(diào) success: function (result) { console.log('壓縮之后圖片尺寸大小: ', result.size); console.log('mime 類型: ', result.type); console.log('實際壓縮率: ', ((file.size - result.size) / file.size * 100).toFixed(2) + '%'); }, // 發(fā)生錯誤 error: function (msg) { console.error(msg); } }; new ImageCompressor(options);
以上就是插件式的解決辦法,更詳細(xì)的文檔,可以在 gitbhub 的官方文檔上查看;插件式解決辦法已經(jīng)在項目中實踐,推薦大家使用~~
寫在最后
以上提供的插件式解決辦法已經(jīng)在項目中實踐,但是存在的問題是,插件控制的壓縮率和實際的壓縮率有一定的出入(不同格式的圖片出入有一定差異),因此壓縮率不好嚴(yán)格控制
到此這篇關(guān)于前端圖片壓縮常見的一些解決辦法的文章就介紹到這了,更多相關(guān)前端圖片壓縮解決內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
兩種不同的方法實現(xiàn)js對checkbox進行全選和反選
這篇文章主要介紹了通過兩種不同的方法實現(xiàn)js對checkbox進行全選和反選,需要的朋友可以參考下2014-05-05在Ajax中使用Flash實現(xiàn)跨域數(shù)據(jù)讀取的實現(xiàn)方法
今天,小子再提供一種使用Flash進行跨域操作的方法。眾所周之,其實Flash的跨域操作也是有限制的,不過,F(xiàn)lash的跨域配置比簡單,只需要在站點根目錄下放置crossdomain.xml即可。2010-12-12TypeScript調(diào)整數(shù)組元素順序算法
數(shù)組類型在TS中可以使用多種方式,比較靈活,下面這篇文章主要給大家介紹了關(guān)于TypeScript調(diào)整數(shù)組元素順序算法的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04JavaScript?setTimeout和setInterval的用法與區(qū)別詳解
Javascript的setTimeOut和setInterval函數(shù)應(yīng)用非常廣泛,它們都用來處理延時和定時任務(wù),下面這篇文章主要給大家介紹了關(guān)于JavaScript?setTimeout和setInterval的用法與區(qū)別,需要的朋友可以參考下2022-04-04