前端實(shí)現(xiàn)圖片壓縮方案總結(jié)(干貨)
前文提要
在Web開發(fā)中,圖片壓縮是一個(gè)常見且重要的需求。隨著高清圖片和多媒體內(nèi)容的普及,如何在保證圖片質(zhì)量的同時(shí)減少其文件大小,對(duì)于提升網(wǎng)頁(yè)加載速度、優(yōu)化用戶體驗(yàn)至關(guān)重要。前端作為用戶與服務(wù)器之間的橋梁,實(shí)現(xiàn)圖片壓縮的功能可以顯著減輕服務(wù)器的負(fù)擔(dān),加快頁(yè)面渲染速度。本文將探討前端實(shí)現(xiàn)圖片壓縮的幾種方法和技術(shù)。
1. 使用HTML5的<canvas>元素
HTML5的<canvas>元素為前端圖片處理提供了強(qiáng)大的能力。通過(guò)JavaScript操作<canvas>,我們可以讀取圖片數(shù)據(jù),對(duì)其進(jìn)行處理(如縮放、裁剪、轉(zhuǎn)換格式等),然后輸出壓縮后的圖片。
步驟概述:
- 讀取圖片:使用
FileReader或Image對(duì)象加載圖片。 - 繪制到
<canvas>:將圖片繪制到<canvas>上,通過(guò)調(diào)整<canvas>的尺寸或繪圖參數(shù)來(lái)控制壓縮效果。 - 導(dǎo)出圖片:使用
canvas.toDataURL()方法將<canvas>內(nèi)容轉(zhuǎn)換為Base64編碼的圖片,或使用canvas.toBlob()方法獲取Blob對(duì)象,以便進(jìn)一步處理或上傳。
示例代碼:
function compressImage(file, quality, callback) {
const reader = new FileReader();
reader.onload = function(e) {
const img = new Image();
img.onload = function() {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 設(shè)置canvas的尺寸,這里可以根據(jù)需要調(diào)整
const MAX_WIDTH = 800;
const MAX_HEIGHT = 600;
let width = img.width;
let height = img.height;
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0, width, height);
// 轉(zhuǎn)換為壓縮后的圖片
canvas.toBlob(function(blob) {
callback(blob);
}, 'image/jpeg', quality);
};
img.src = e.target.result;
};
reader.readAsDataURL(file);
}
// 使用示例
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', function(e) {
const file = e.target.files[0];
compressImage(file, 0.7, function(blob) {
// 處理壓縮后的圖片,如上傳或顯示
console.log(blob);
});
});
2. 利用第三方庫(kù)(推薦)
除了原生JavaScript和HTML5外,還有許多優(yōu)秀的第三方庫(kù)可以幫助我們更方便地實(shí)現(xiàn)圖片壓縮,如image-magic-adapter、compressorjs、pica等。這些庫(kù)通常提供了更豐富的配置選項(xiàng)和更好的兼容性支持。
特別推薦的庫(kù): image-magic-adapter
這個(gè)三方庫(kù)是國(guó)內(nèi)開發(fā)者提供的,他集成許多圖片處理能力,包括“圖片壓縮”、“圖片格式轉(zhuǎn)換”、“圖片加水印”等等,非常方便,而且這個(gè)庫(kù)還有官網(wǎng)也可以直接使用這些功能.
庫(kù)官網(wǎng):https://www.npmjs.com/package/image-magic-adapter
在線圖片處理工具官網(wǎng):https://luckycola.com.cn/public/dist/imageTool.html
使用 image-magic-adapter示例:
// 引入image-magic-adapter
import ImageMagicAdapter from 'image-magic-adapter';
let ImageCompressorCls = ImageMagicAdapter.ImageCompressorCls;
const imageCompressor = new ImageCompressorCls(); // 默認(rèn)壓縮質(zhì)量
// -----------------------------------------圖片壓縮-----------------------------------------
document.getElementById('quality').addEventListener('input', () => {
const quality = parseFloat(document.getElementById('quality').value);
imageCompressor.quality = 1 - quality; // 更新壓縮質(zhì)量
console.log('更新后的壓縮質(zhì)量:', imageCompressor.quality);
});
document.getElementById('compress').addEventListener('click', async () => {
const fileInput = document.getElementById('upload');
if (!fileInput.files.length) {
alert('請(qǐng)上傳圖片');
return;
}
const files = Array.from(fileInput.files);
const progress = document.getElementById('progress');
const outputContainer = document.getElementById('outputContainer');
const downloadButton = document.getElementById('download');
const progressText = document.getElementById('progressText');
outputContainer.innerHTML = '';
downloadButton.style.display = 'none';
progress.style.display = 'block';
progress.value = 0;
progressText.innerText = '';
// compressImages參數(shù)說(shuō)明:
// 第一個(gè)參數(shù): files:需要壓縮的文件數(shù)組
// 第二個(gè)參數(shù): callback:壓縮完成后的回調(diào)函數(shù)
// 第三個(gè)參數(shù): 若是壓縮png/bmp格式,輸出是否保留png/bmp格式,默認(rèn)為true(建議設(shè)置為false)
// 注意:如果 第三個(gè)參數(shù)設(shè)置true壓縮png/bmp格式后的輸出的文件為原格式(png/bmp)且壓縮效果不佳,就需要依賴設(shè)置scaleFactor來(lái)調(diào)整壓縮比例(0-1);如果設(shè)置為false,輸出為image/jpeg格式且壓縮效果更好。
// 設(shè)置caleFactor為0-1,值越大,壓縮比例越小,值越小,壓縮比例越大(本質(zhì)是改變圖片的尺寸),例: imageCompressor.scaleFactor = 0.5;
await imageCompressor.compressImages(files, (completed, total) => {
const outputImg = document.createElement('img');
outputImg.src = imageCompressor.compressedImages[completed - 1];
outputContainer.appendChild(outputImg);
progress.value = (completed / total) * 100;
progressText.innerText = `已完成文件數(shù): ${completed} / 總文件數(shù): ${total}`;
if (completed === total) {
downloadButton.style.display = 'inline-block';
}
}, false);
downloadButton.onclick = () => {
if (imageCompressor.compressedImages.length > 0) {
imageCompressor.downloadZip(imageCompressor.compressedImages);
}
};
});
<h4>圖片壓縮Demo</h4>
<input type="file" id="upload" accept="image/*" multiple />
<br>
<label for="quality">壓縮比率:(比率越大壓縮越大,圖片質(zhì)量越低)</label>
<input type="range" id="quality" min="0" max="0.9" step="0.1" required value="0.5"/>
<br>
<button id="compress">壓縮圖片</button>
<br>
<progress id="progress" value="0" max="100" style="display: none;"></progress>
<br />
<span id="progressText"></span>
<br>
<div id="outputContainer"></div>
<br>
<button id="download" style="display: none;">下載已壓縮圖片</button>
3. gif圖片壓縮(拓展)
GIF(Graphics Interchange Format)圖片是一種廣泛使用的圖像文件格式,特別適合用于顯示索引顏色圖像(如簡(jiǎn)單的圖形、圖標(biāo)和某些類型的圖片),同時(shí)也支持動(dòng)畫。盡管GIF圖片本身可以具有壓縮特性,但在前端和后端進(jìn)行壓縮處理時(shí),存在幾個(gè)關(guān)鍵考慮因素,這些因素可能導(dǎo)致在前端直接壓縮GIF不如在后端處理更為有效或合理。
下面提供一個(gè)厚后端通過(guò)node實(shí)現(xiàn)gif壓縮的方案:
1、下載imagemin、imagemin-gifsicle和image-size庫(kù)
2、注意依賴的庫(kù)的版本,不然可能會(huì)報(bào)錯(cuò)
"image-size": "^1.1.1",
"imagemin": "7.0.1",
"imagemin-gifsicle": "^7.0.0",
node壓縮gif實(shí)現(xiàn)如下:
const imagemin = require('imagemin');
const imageminGifsicle = require('imagemin-gifsicle');
const sizeOf = require('image-size');
// 壓縮 GIF colors[0-256]
const compressGifImgFn = async (inputBase64, colors = 200, successFn = () => {}, failFn = () => {}) => {
try {
if (inputBase64.length <= 10) {
failFn && failFn('inputBase64 無(wú)效')
return;
}
// 獲取輸入 GIF 的尺寸
const originalSize = getBase64Size(inputBase64);
console.log('Original Size:', originalSize);
// 轉(zhuǎn)換 Base64 為 Buffer
const inputBuffer = base64ToBuffer(inputBase64);
const outputBuffer = await imagemin.buffer(inputBuffer, {
plugins: [
imageminGifsicle({
// interlaced的作用 是,是否對(duì) GIF 進(jìn)行隔行掃描
interlaced: true,
// optimizationLevel的作用是,設(shè)置壓縮的質(zhì)量,0-3
optimizationLevel: 3,
// // progressive的作用是,是否對(duì) GIF 進(jìn)行漸進(jìn)式壓縮
// progressive: true,
// // palette的作用是,是否對(duì) GIF 進(jìn)行調(diào)色板優(yōu)化
// palette: true,
// // colorspace的作用是,是否對(duì) GIF 進(jìn)行色彩空間轉(zhuǎn)換
// colorspace: true,
colors
})
]
});
// 轉(zhuǎn)換壓縮后的 Buffer 為 Base64
const outputBase64 = bufferToBase64(outputBuffer);
// 獲取壓縮后 GIF 的尺寸
const compressedSize = getBase64Size(outputBase64);
console.log('Compressed Size:', compressedSize);
// 輸出壓縮后的 Base64 GIF
// console.log(outputBase64);
let gifCompressRes = {
outputBase64,
compressedSize,
originalSize
}
successFn && successFn(gifCompressRes);
} catch (error) {
console.error('Error compressing GIF:', error);
failFn && failFn(error)
}
};
// 將 Base64 字符串轉(zhuǎn)換為 Buffer
function base64ToBuffer(base64) {
const base64Data = base64.split(',')[1]; // 如果是 data URL, 刪除前綴
return Buffer.from(base64Data, 'base64');
}
// 將 Buffer 轉(zhuǎn)換為 Base64 字符串
function bufferToBase64(buffer) {
return `data:image/gif;base64,${buffer.toString('base64')}`;
}
//獲取base64圖片大小,返回kb數(shù)字
function getBase64Size(base64url) {
try {
//把頭部去掉
let str = base64url.replace('data:image/png;base64,', '');
// 找到等號(hào),把等號(hào)也去掉
let equalIndex = str.indexOf('=');
if (str.indexOf('=') > 0) {
str = str.substring(0, equalIndex);
}
// 原來(lái)的字符流大小,單位為字節(jié)
let strLength = str.length;
// 計(jì)算后得到的文件流大小,單位為字節(jié)
let fileLength = parseInt(strLength - (strLength / 8) * 2);
// 由字節(jié)轉(zhuǎn)換為kb
let size = "";
size = (fileLength / 1024).toFixed(2);
let sizeStr = size + ""; //轉(zhuǎn)成字符串
let index = sizeStr.indexOf("."); //獲取小數(shù)點(diǎn)處的索引
let dou = sizeStr.substr(index + 1, 2) //獲取小數(shù)點(diǎn)后兩位的值
if (dou == "00") { //判斷后兩位是否為00,如果是則刪除00
return sizeStr.substring(0, index) + sizeStr.substr(index + 3, 2)
}
return size;
} catch (error) {
console.log('getBase64Size error:', error);
return 0;
}
};
注意事項(xiàng)
- 壓縮質(zhì)量與文件大小:壓縮質(zhì)量越高,圖片質(zhì)量越好,但文件大小也越大;反之亦然。需要根據(jù)實(shí)際需求調(diào)整。
- 兼容性:雖然現(xiàn)代瀏覽器普遍支持
<canvas>和Blob等特性,但在一些老舊瀏覽器上可能存在問題,需要做好兼容性處理。 - 性能考慮:對(duì)于大圖片或高頻率的圖片處理,前端壓縮可能會(huì)占用較多CPU資源,影響頁(yè)面性能。
總結(jié)
到此這篇關(guān)于前端實(shí)現(xiàn)圖片壓縮方案的文章就介紹到這了,更多相關(guān)前端實(shí)現(xiàn)圖片壓縮內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript使用DeviceOne開發(fā)實(shí)戰(zhàn)(三)仿微信應(yīng)用
這篇文章主要介紹了JavaScript使用DeviceOne開發(fā)實(shí)戰(zhàn)(三)仿微信應(yīng)用的相關(guān)資料,需要的朋友可以參考下2015-12-12
js 用于檢測(cè)類數(shù)組對(duì)象的函數(shù)方法
下面小編就為大家?guī)?lái)一篇js 用于檢測(cè)類數(shù)組對(duì)象的函數(shù)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05
select隱藏選中值對(duì)應(yīng)的id,顯示其它id的簡(jiǎn)單實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇select隱藏選中值對(duì)應(yīng)的id,顯示其它id的簡(jiǎn)單實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-08-08
MC Dialog js彈出層 完美兼容多瀏覽器(5.6更新)
MC.Dialog 是由肖毅(YesSky) 開發(fā)一款界面絢麗美觀 操作簡(jiǎn)單易用的一款js彈出層 MC.Dialog 是經(jīng)過(guò)嚴(yán)格了測(cè)試的 兼容目前ie7+ 以及其他非ie核心的瀏覽器 完美模擬瀏覽器自帶對(duì)話框功能2010-05-05
微信小程序登錄態(tài)和檢驗(yàn)注冊(cè)過(guò)沒的app.js寫法
這篇文章主要介紹了小程序登錄態(tài)和檢驗(yàn)注冊(cè)過(guò)沒的app.js寫法, 本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的借鑒價(jià)值,需要的朋友可以參考下2019-05-05
JavaScript代碼應(yīng)該放在HTML代碼哪個(gè)位置比較好?
這篇文章主要介紹了JavaScript代碼應(yīng)該放在HTML代碼哪個(gè)位置比較好?本文總結(jié)了多種放置JS代碼的方法,需要的朋友可以參考下2014-10-10
JavaScript控制網(wǎng)頁(yè)平滑滾動(dòng)到指定元素位置的方法
這篇文章主要介紹了JavaScript控制網(wǎng)頁(yè)平滑滾動(dòng)到指定元素位置的方法,實(shí)例分析了javascript操作頁(yè)面滾動(dòng)的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04

