前端实现图片压缩(干货总结)

LuckyCola2023 2024-10-27 08:03:01 阅读 67

前端实现图片压缩方案总结

前文提要1. 使用HTML5的`<canvas>`元素步骤概述:示例代码:

2. 利用第三方库(推荐)使用 image-magic-adapter示例:

3. gif图片压缩(拓展)node压缩gif实现如下:

注意事项


⚠️⚠️文前推荐一下👉

前端必备工具推荐网站(图床、API和ChatAI、智能AI简历、AI思维导图神器等实用工具):

站点入口:http://luckycola.com.cn/


前文提要

在Web开发中,图片压缩是一个常见且重要的需求。随着高清图片和多媒体内容的普及,如何在保证图片质量的同时减少其文件大小,对于提升网页加载速度、优化用户体验至关重要。前端作为用户与服务器之间的桥梁,实现图片压缩的功能可以显著减轻服务器的负担,加快页面渲染速度。本文将探讨前端实现图片压缩的几种方法和技术。

1. 使用HTML5的<code><canvas>元素

HTML5的<canvas>元素为前端图片处理提供了强大的能力。通过JavaScript操作<canvas>,我们可以读取图片数据,对其进行处理(如缩放、裁剪、转换格式等),然后输出压缩后的图片。

步骤概述:

读取图片:使用FileReaderImage对象加载图片。绘制到<canvas>:将图片绘制到<canvas>上,通过调整<canvas>的尺寸或绘图参数来控制压缩效果。导出图片:使用canvas.toDataURL()方法将<canvas>内容转换为Base64编码的图片,或使用canvas.toBlob()方法获取Blob对象,以便进一步处理或上传。

示例代码:

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');

// 设置canvas的尺寸,这里可以根据需要调整

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);

// 转换为压缩后的图片

canvas.toBlob(function(blob) {

callback(blob);

}, 'image/jpeg', quality);

};

img.src = e.target.result;

};

reader.readAsDataURL(file);

}

// 使用示例

const fileInput = document.querySelector('input[type="file"]');code>

fileInput.addEventListener('change', function(e) { -- -->

const file = e.target.files[0];

compressImage(file, 0.7, function(blob) {

// 处理压缩后的图片,如上传或显示

console.log(blob);

});

});

2. 利用第三方库(推荐)

除了原生JavaScript和HTML5外,还有许多优秀的第三方库可以帮助我们更方便地实现图片压缩,如image-magic-adapter、compressorjspica等。这些库通常提供了更丰富的配置选项和更好的兼容性支持。

特别推荐的库: image-magic-adapter

这个三方库是国内开发者提供的,他集成许多图片处理能力,包括“图片压缩”、“图片格式转换”、“图片加水印”等等,非常方便,而且这个库还有官网也可以直接使用这些功能.

库官网:https://www.npmjs.com/package/image-magic-adapter

在线图片处理工具官网: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(); // 默认压缩质量

// -----------------------------------------图片压缩-----------------------------------------

document.getElementById('quality').addEventListener('input', () => {

const quality = parseFloat(document.getElementById('quality').value);

imageCompressor.quality = 1 - quality; // 更新压缩质量

console.log('更新后的压缩质量:', imageCompressor.quality);

});

document.getElementById('compress').addEventListener('click', async () => {

const fileInput = document.getElementById('upload');

if (!fileInput.files.length) {

alert('请上传图片');

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参数说明:

// 第一个参数: files:需要压缩的文件数组

// 第二个参数: callback:压缩完成后的回调函数

// 第三个参数: 若是压缩png/bmp格式,输出是否保留png/bmp格式,默认为true(建议设置为false)

// 注意:如果 第三个参数设置true压缩png/bmp格式后的输出的文件为原格式(png/bmp)且压缩效果不佳,就需要依赖设置scaleFactor来调整压缩比例(0-1);如果设置为false,输出为image/jpeg格式且压缩效果更好。

// 设置caleFactor为0-1,值越大,压缩比例越小,值越小,压缩比例越大(本质是改变图片的尺寸),例: 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 = `已完成文件数: ${ completed} / 总文件数: ${ 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 />code>

<br>

<label for="quality">压缩比率:(比率越大压缩越大,图片质量越低)</label>code>

<input type="range" id="quality" min="0" max="0.9" step="0.1" required value="0.5"/>code>

<br>

<button id="compress">压缩图片</button>code>

<br>

<progress id="progress" value="0" max="100" style="display: none;"></progress>code>

<br />

<span id="progressText"></span>code>

<br>

<div id="outputContainer"></div>code>

<br>

<button id="download" style="display: none;">下载已压缩图片</button>code>

3. gif图片压缩(拓展)

GIF(Graphics Interchange Format)图片是一种广泛使用的图像文件格式,特别适合用于显示索引颜色图像(如简单的图形、图标和某些类型的图片),同时也支持动画。尽管GIF图片本身可以具有压缩特性,但在前端和后端进行压缩处理时,存在几个关键考虑因素,这些因素可能导致在前端直接压缩GIF不如在后端处理更为有效或合理。

下面提供一个厚后端通过node实现gif压缩的方案:

1、下载imagemin、imagemin-gifsicle和image-size库

2、注意依赖的库的版本,不然可能会报错

"image-size": "^1.1.1",

"imagemin": "7.0.1",

"imagemin-gifsicle": "^7.0.0",

node压缩gif实现如下:

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 无效')

return;

}

// 获取输入 GIF 的尺寸

const originalSize = getBase64Size(inputBase64);

console.log('Original Size:', originalSize);

// 转换 Base64 为 Buffer

const inputBuffer = base64ToBuffer(inputBase64);

const outputBuffer = await imagemin.buffer(inputBuffer, {

plugins: [

imageminGifsicle({

// interlaced的作用 是,是否对 GIF 进行隔行扫描

interlaced: true,

// optimizationLevel的作用是,设置压缩的质量,0-3

optimizationLevel: 3,

// // progressive的作用是,是否对 GIF 进行渐进式压缩

// progressive: true,

// // palette的作用是,是否对 GIF 进行调色板优化

// palette: true,

// // colorspace的作用是,是否对 GIF 进行色彩空间转换

// colorspace: true,

colors

})

]

});

// 转换压缩后的 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 字符串转换为 Buffer

function base64ToBuffer(base64) {

const base64Data = base64.split(',')[1]; // 如果是 data URL, 删除前缀

return Buffer.from(base64Data, 'base64');

}

// 将 Buffer 转换为 Base64 字符串

function bufferToBase64(buffer) {

return `data:image/gif;base64,${ buffer.toString('base64')}`;

}

//获取base64图片大小,返回kb数字

function getBase64Size(base64url) {

try {

//把头部去掉

let str = base64url.replace('data:image/png;base64,', '');

// 找到等号,把等号也去掉

let equalIndex = str.indexOf('=');

if (str.indexOf('=') > 0) {

str = str.substring(0, equalIndex);

}

// 原来的字符流大小,单位为字节

let strLength = str.length;

// 计算后得到的文件流大小,单位为字节

let fileLength = parseInt(strLength - (strLength / 8) * 2);

// 由字节转换为kb

let size = "";

size = (fileLength / 1024).toFixed(2);

let sizeStr = size + ""; //转成字符串

let index = sizeStr.indexOf("."); //获取小数点处的索引

let dou = sizeStr.substr(index + 1, 2) //获取小数点后两位的值

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;

}

};

注意事项

压缩质量与文件大小:压缩质量越高,图片质量越好,但文件大小也越大;反之亦然。需要根据实际需求调整。兼容性:虽然现代浏览器普遍支持<canvas>和Blob等特性,但在一些老旧浏览器上可能存在问题,需要做好兼容性处理。性能考虑:对于大图片或高频率的图片处理,前端压缩可能会占用较多CPU资源,影响页面性能。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。