前端圖片壓縮常見的一些解決辦法
問題產(chǎn)生背景
在某一h5的項(xiàng)目,要求上傳的圖片格式為 base64 , 問題是用戶上傳的圖片基本都在MB 級(jí)別,轉(zhuǎn)base64 以后,圖片的體積會(huì)增大30%以上,隨著圖片的體積增加,轉(zhuǎn)換的base64 格式文件體積越大,如果此時(shí)前端不對(duì)用戶上傳的圖片體積進(jìn)行壓縮,可能會(huì)導(dǎo)致服務(wù)器壓力過大,從而崩潰;
解決辦法
1、使用純 js 解決
解決思路:
1、通過 input 文件選擇框拿到要上傳的圖片文件file
2、FileReader.readAsDataURL() 讀取 file 內(nèi)容。完成后 result 屬性中將包含一個(gè) data: URL格式的 Base64字符串以表示所讀取文件的內(nèi)容。
3、創(chuàng)建一個(gè) img 標(biāo)簽,將 FileReader 對(duì)象返回的 base64 格式 url 給到一個(gè) 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 方法會(huì)讀取指定的 Blob 或 File 對(duì)象。讀取操作完成的時(shí)候,readyState 會(huì)變成已完成DONE,并觸發(fā) loadend (en-US) 事件, // 同時(shí) result 屬性將包含一個(gè)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對(duì)圖片進(jìn)行裁剪,這里設(shè)置為圖片的原始尺寸 canvas.width = w; canvas.height = h; const ctx = canvas.getContext("2d"); // canvas中,png轉(zhuǎn)jpg會(huì)變黑底,所以先給canvas鋪一張白底 ctx.fillStyle = "#fff"; // fillRect()方法繪制一個(gè)填充了內(nèi)容的矩形,這個(gè)矩形的開始點(diǎn)(左上點(diǎn))在 // (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)圖片達(dá)到圖片壓縮效果 // 返回一個(gè)包含圖片展示的 data URI base64 在指定圖片格式為 image/jpeg 或 image/webp的情況下, // 可以從 0 到 1 的區(qū)間內(nèi)選擇圖片的質(zhì)量。如果超出取值范圍,將會(huì)使用默認(rèn)值 0.92。其他參數(shù)會(huì)被忽略。 const dataUrl = canvas.toDataURL("image/jpeg", 0.8); // base64格式文件轉(zhuǎn)成Blob文件格式 return blobFile = dataURLtoBlob(dataUrl); // 拿到這個(gè)blobFile文件就可以上傳給服務(wù)端 console.log("壓縮后的file----------", blobFile); }; }; } // canvas生成的格式為base64,如果需要Blob格式可按如下進(jìn)行轉(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 }); },
使用以上方法存在缺點(diǎn):
- 壓縮后的格式只能是 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瀏覽器會(huì)按其方向呈現(xiàn)圖像,這個(gè)選項(xiàng)可以控制恢復(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('實(shí)際壓縮率: ', ((file.size - result.size) / file.size * 100).toFixed(2) + '%'); }, // 發(fā)生錯(cuò)誤 error: function (msg) { console.error(msg); } }; new ImageCompressor(options);
以上就是插件式的解決辦法,更詳細(xì)的文檔,可以在 gitbhub 的官方文檔上查看;插件式解決辦法已經(jīng)在項(xiàng)目中實(shí)踐,推薦大家使用~~
寫在最后
以上提供的插件式解決辦法已經(jīng)在項(xiàng)目中實(shí)踐,但是存在的問題是,插件控制的壓縮率和實(shí)際的壓縮率有一定的出入(不同格式的圖片出入有一定差異),因此壓縮率不好嚴(yán)格控制
到此這篇關(guān)于前端圖片壓縮常見的一些解決辦法的文章就介紹到這了,更多相關(guān)前端圖片壓縮解決內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
配置eslint規(guī)范項(xiàng)目代碼風(fēng)格
這篇文章主要介紹了配置eslint規(guī)范項(xiàng)目代碼風(fēng)格,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-03-03兩種不同的方法實(shí)現(xiàn)js對(duì)checkbox進(jìn)行全選和反選
這篇文章主要介紹了通過兩種不同的方法實(shí)現(xiàn)js對(duì)checkbox進(jìn)行全選和反選,需要的朋友可以參考下2014-05-05js canvas實(shí)現(xiàn)擦除動(dòng)畫
在移動(dòng)設(shè)備上將某張圖片擦掉顯示另一張圖片,利用canvas來實(shí)現(xiàn)這篇文章就為大家詳細(xì)介紹了js canvas實(shí)現(xiàn)擦除動(dòng)畫的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-07-07在Ajax中使用Flash實(shí)現(xiàn)跨域數(shù)據(jù)讀取的實(shí)現(xiàn)方法
今天,小子再提供一種使用Flash進(jìn)行跨域操作的方法。眾所周之,其實(shí)Flash的跨域操作也是有限制的,不過,F(xiàn)lash的跨域配置比簡(jiǎn)單,只需要在站點(diǎn)根目錄下放置crossdomain.xml即可。2010-12-12JS實(shí)現(xiàn)回到頁面頂部動(dòng)畫效果的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)硪黄狫S實(shí)現(xiàn)回到頁面頂部動(dòng)畫效果的簡(jiǎn)單實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-05-05TypeScript調(diào)整數(shù)組元素順序算法
數(shù)組類型在TS中可以使用多種方式,比較靈活,下面這篇文章主要給大家介紹了關(guān)于TypeScript調(diào)整數(shù)組元素順序算法的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04JavaScript?setTimeout和setInterval的用法與區(qū)別詳解
Javascript的setTimeOut和setInterval函數(shù)應(yīng)用非常廣泛,它們都用來處理延時(shí)和定時(shí)任務(wù),下面這篇文章主要給大家介紹了關(guān)于JavaScript?setTimeout和setInterval的用法與區(qū)別,需要的朋友可以參考下2022-04-04