it编程 > 编程语言 > Javascript

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

37人参与 2025-02-14 Javascript

前文提要

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

1. 使用html5的<canvas>元素

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

步骤概述:

示例代码:

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"]');
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 />
    <br>
    <label for="quality">压缩比率:(比率越大压缩越大,图片质量越低)</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)图片是一种广泛使用的图像文件格式,特别适合用于显示索引颜色图像(如简单的图形、图标和某些类型的图片),同时也支持动画。尽管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;
    }
  };

注意事项

总结 

到此这篇关于前端实现图片压缩方案的文章就介绍到这了,更多相关前端实现图片压缩内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)
打赏 微信扫一扫 微信扫一扫

您想发表意见!!点此发布评论

推荐阅读

Next.js中处理时区的常用方案推荐

02-14

纯前端生成PDF(jsPDF)并下载保存或上传到OSS的代码示例

02-14

JavaScript中的6种变体函数的区别和应用

02-14

在webview中如何跳回小程序步骤详解

02-14

JavaScript读取XML文件的几种方法

02-14

在前端中Proj4.js使用简单介绍及进阶应用

02-14

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论