使用Canvas?API實現(xiàn)前端圖片壓縮功能
前言
最近我在工作上遇到用戶上傳大尺寸圖片的需求,發(fā)現(xiàn)直接上傳原始圖片會消耗過多帶寬和存儲空間。于是在網(wǎng)上找了一些像 圖片壓縮網(wǎng)站 這樣的工具能在瀏覽器里直接完成壓縮,無需上傳到服務(wù)器,這讓我很受啟發(fā)。經(jīng)過研究,我找到了使用Canvas API的簡單實現(xiàn)方案,下面是自己實現(xiàn)的代碼和想法。
核心實現(xiàn)原理
Canvas圖片壓縮主要利用以下技術(shù)流程:
- 將原始圖片繪制到Canvas畫布上
- 調(diào)整Canvas尺寸以實現(xiàn)分辨率壓縮
- 使用有損編碼(如JPEG)和可調(diào)質(zhì)量參數(shù)輸出圖片
- 將結(jié)果轉(zhuǎn)換為Blob或Base64格式
關(guān)鍵代碼實現(xiàn)
1. 圖片加載與繪制
function loadImage(file) { return new Promise((resolve, reject) => { const img = new Image(); const url = URL.createObjectURL(file); img.onload = () => { URL.revokeObjectURL(url); resolve(img); }; img.onerror = (e) => { reject(e); }; img.src = url; }); }
2. 核心壓縮函數(shù)
async function compressImage(file, options = {}) { const { quality = 0.8, maxWidth = 800, maxHeight = 800, mimeType = 'image/jpeg' } = options; // 加載原始圖片 const img = await loadImage(file); // 計算縮放比例 const [newWidth, newHeight] = calculateSize(img, maxWidth, maxHeight); // 創(chuàng)建canvas并繪制 const canvas = document.createElement('canvas'); canvas.width = newWidth; canvas.height = newHeight; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0, newWidth, newHeight); // 轉(zhuǎn)換為Blob對象 return new Promise((resolve) => { canvas.toBlob( (blob) => resolve(blob), mimeType, quality ); }); } // 輔助函數(shù):計算新尺寸 function calculateSize(img, maxWidth, maxHeight) { let width = img.width; let height = img.height; // 計算縮放比例 if (width > height) { if (width > maxWidth) { height = Math.round((height * maxWidth) / width); width = maxWidth; } } else { if (height > maxHeight) { width = Math.round((width * maxHeight) / height); height = maxHeight; } } return [width, height]; }
3. 使用示例
const fileInput = document.querySelector('input[type="file"]'); fileInput.addEventListener('change', async (e) => { const file = e.target.files[0]; if (!file) return; try { const compressedBlob = await compressImage(file, { quality: 0.7, maxWidth: 1024, maxHeight: 1024 }); // 使用壓縮后的Blob console.log(`原始大小: ${file.size} bytes`); console.log(`壓縮后: ${compressedBlob.size} bytes`); // 可以上傳到服務(wù)器或提供給用戶下載 } catch (error) { console.error('壓縮失敗:', error); } });
關(guān)鍵參數(shù)說明
quality (0-1) : 控制JPEG壓縮質(zhì)量,數(shù)值越小壓縮率越高
maxWidth/maxHeight: 限制圖片最大尺寸,實現(xiàn)分辨率壓縮
mimeType: 可指定為'image/jpeg'(有損)、'image/png'(無損)等
瀏覽器兼容性
Canvas壓縮功能在現(xiàn)代瀏覽器中支持良好,包括:
- Chrome 50+
- Firefox 50+
- Safari 10+
- Edge 15+
方法補充
使用canvas實現(xiàn)圖片壓縮上傳
實現(xiàn)思路
- 使用 FileReader 對象獲取本地文件(使用文件選擇 input 元素)的 base64 內(nèi)容
- 使用 context.drawImage 把獲取到的文件畫在 canvas 上
- 使用 canvas.toBlob 對圖片做質(zhì)量壓縮
完整代碼
/** * 對選中的圖片文件處理 * * @param {obj} event 圖片文件 * */ uploadImg (event) { // 為選擇文件返回 if (!event.target.files[0]) return; let file = event.target.files[0], fileName = file.name.substring(file.name.lastIndexOf(".") + 1).toLowerCase(); // 文件格式校驗 if (fileName != "jpg" && fileName != "png" && fileName != "gif" ) { this.$store.commit('setPrompt', {status: true, text: '請選擇正確的圖片格式上傳(jpg,png,gif)'}) return } // gif圖片格式不做處理,其他靜態(tài)圖片做質(zhì)量壓縮處理以減小圖片大小 if (fileName == 'gif') { this.uploadApi(file, file.name) } else { let _this = this; // 壓縮圖片需要的一些元素和對象 let reader = new FileReader(), img = new Image(); reader.readAsDataURL(file); // 縮放圖片需要的canvas let canvas = document.createElement('canvas'); let context = canvas.getContext('2d'); // base64地址圖片加載完畢后 img.onload = function() { // 圖片原始尺寸 let originWidth = this.width; let originHeight = this.height; canvas.width = originWidth; canvas.height = originHeight; // 清除畫布 context.clearRect(0, 0, originWidth, originHeight); // 圖片壓縮 context.drawImage(img, 0, 0, originWidth, originHeight); // canvas轉(zhuǎn)為blob并上傳 canvas.toBlob(function(blob) { _this.uploadApi(blob, file.name) }, file.type == 'image/gif' ? 'image/gif' : "image/jpeg", 0.6); } // 文件base64化,以便獲知圖片原始尺寸 reader.onload = function(e) { img.src = e.target.result; }; } }, /** * 上傳選中的圖片文件 * * @param {obj} file 圖片文件 * @param {string} fileName 文件名稱 * */ uploadApi(file, fileName) { let formData = new FormData() formData.append('img', file, fileName) axios.post('/upload/upload-img', formData, {headers: {'Content-Type': 'multipart/form-data'}}).then((res) => { if (res.data.code == 200) { this.img_list.splice(this.img_list.length, 1, res.data.url) } else { this.$store.commit('setPrompt', {status: true, text: res.data.message}) } }) }
到此這篇關(guān)于使用Canvas API實現(xiàn)前端圖片壓縮功能的文章就介紹到這了,更多相關(guān)Canvas圖片壓縮內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js中substring和substr兩者區(qū)別和使用方法
這篇文章主要介紹了js中substring和substr兩者區(qū)別和使用方法,每一個步驟都有相應(yīng)的文字介紹,感興趣的小伙伴們可以參考一下2015-11-11網(wǎng)絡(luò)復(fù)制內(nèi)容時常用的正則+editplus
有時侯我們在拷貝網(wǎng)頁上的內(nèi)容的時候,總是有一些,開頭的數(shù)字,需要替換掉2006-11-11next.js?getServerSideProps源碼解析
這篇文章主要為大家介紹了next.js?getServerSideProps源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-10-10JavaScript位置與大?。?)之正確理解和運用與尺寸大小相關(guān)的DOM屬性
這篇文章主要介紹了JavaScript位置與大小(1)——正確理解和運用與尺寸大小相關(guān)的DOM屬性的相關(guān)資料,需要的朋友可以參考下2015-12-12