JavaScript实现图像压缩的几种方案与代码示例

作者:窗边听雨

时间:2026-10-26

浏览:134

本文详解JavaScript实现图像压缩的多种方法。涵盖利用Canvas API进行基础压缩、通过Web Worker避免UI阻塞、以及处理Base64指定大小压缩的策略。同时介绍了canvas-toBlob.js、lwip等常用第三方库,并提供完整代码示例与性能优化建议。

文章目录

在 JavaScript 中,可以通过 Canvas 和 Web Workers 技术来实现图像的压缩处理。

利用 Canvas 时,可将图像绘制到画布上,随后调用其提供的 toBlob() 或 toDataURL() 方法,并指定图像质量参数,从而转换为不同格式或实现压缩效果。

借助 Web Workers,可以在后台线程中执行图像压缩任务,从而避免阻塞主 UI 线程,提升用户体验。

受限于 JavaScript 的安全机制,代码无法直接操作本地文件系统。因此,该方案通常应用于浏览器端:用户上传图像后,由 JavaScript 进行压缩处理,随后再上传至服务端进行后续处理。

JavaScript 生态中存在一些第三方库可辅助图像压缩,例如:

  • canvas-toBlob.js:为不支持 toBlob() 的旧版浏览器提供 polyfill 支持。
  • lwip:一个 JavaScript 图像处理库,支持图像的压缩、旋转和裁剪等功能。
  • browser-image-resizer:基于 Canvas 和 Web Workers 构建的图像压缩库。
  • jpeg-js:纯 JavaScript 实现的 JPEG 压缩库,兼容浏览器和 Node.js 环境。

使用上述库进行压缩时需注意性能瓶颈。处理大型图像时,压缩过程可能耗时较长。建议在用户上传图像时展示加载条或提示信息,以告知用户压缩正在进行中。

一、简单压缩

结合 JavaScript 与 Canvas 进行图像压缩的基本流程是:利用 drawImage() 将图像绘制到 Canvas 上,再通过 toDataURL() 将其转换为 Data URL 格式。Data URL 允许将数据直接嵌入 URL,无需网络请求即可在浏览器中加载图像。

调用 toDataURL() 时,可通过第二个参数指定图像质量。该参数取值范围为 0 到 1,分别代表最低和最高质量百分比。

以下是一个使用 Canvas 和 JavaScript 进行图像压缩的示例代码:

// 获取 canvas 元素
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

// 创建 Image 对象
var img = new Image();
img.src = 'image.jpg';
img.onload = function() {
  // 绘制图像到 canvas
  canvas.width = img.width;
  canvas.height = img.height;
  ctx.drawImage(img, 0, 0, img.width, img.height);
  
  // 使用 toDataURL 方法压缩图像
  var dataUrl = canvas.toDataURL('image/jpeg', 0.5);
  
  // 使用新的 Data URL 更新图像
  img.src = dataUrl;
}

此示例将图片以 JPEG 格式进行压缩,质量设定为 50%。压缩后的图像数据会被重新赋值给 img.src,通过调整其他参数可获得不同的压缩效果。

二、使用 Canvas 将 Base64 图像压缩至指定文件大小以内

1、方法一

首先,使用 atob() 函数将 Base64 图像数据解码为二进制字符串,接着创建一个新的 Blob 对象,并利用 FileReader 读取该 Blob 对象。

随后,使用 Canvas 的 drawImage() 方法将图像绘制到画布上,并通过 canvas.toBlob() 方法将结果转换为 Blob 对象。

最后,检查生成 Blob 的大小是否超过预设的最大值。若超出,则降低图像质量重新压缩,直至文件大小小于指定上限。

以下是一个示例代码:

var maxSize = 100 * 1024; // 最大文件大小为100KB
var img = new Image();
img.src = base64Image;
img.onload = function () {
    var canvas = document.createElement('canvas');
    var ctx = canvas.getContext('2d');
    var width = img.width;
    var height = img.height;
    canvas.width = width;
    canvas.height = height;
    ctx.drawImage(img, 0, 0, width, height);
    var quality = 0.8;
    var resultBlob;
    do {
        canvas.toBlob(function (blob) {
            resultBlob = blob;
        }, 'image/jpeg', quality);
        quality -= 0.1;
    } while (resultBlob.size > maxSize && quality > 0.1);
    // do something with resultBlob, like create a new image from it or save it.
}

该示例利用 Canvas 将 Base64 图像压缩至指定的最大文件大小限制内。代码使用 do-while 循环不断降低图像质量,直到文件大小符合限制要求。最终生成的 resultBlob 对象可用于更新页面图像或存储至服务器。

值得注意的是,此示例中每次压缩质量减少 0.1。若压缩后文件大小仍超出限制,可能需要调整该减量或采用其他策略(如更改分辨率)。由于每次仅减少 0.1,处理过程可能耗时较长,实际应用中需根据具体需求进行调整。

2、方法二

采用递归方式处理可避免在压缩过程中因循环导致页面提示无法显示的问题。

// 计算base64编码图片大小
function getBase64ImageSize(base64) {
    const indexBase64 = base64.indexOf('base64,');
    if (indexBase64 < 0) return -1;
    const str = base64.substr(indexBase64 + 6);
    // 大小单位:字节
    return (str.length * 0.75).toFixed(2);
}

/**
 * 	图像压缩,默认同比例压缩
 * @param {Object} imgPath
 *	图像base64编码字符串或图像可访问路径
 * @param {Object} obj
 *	obj 对象 有 width, height, quality(0-1)
 * @param {Object} maxSize
 *	指定压缩后的文件大小,单位:字节
 * @param {Object} callback
 *	回调函数有一个参数,base64的字符串数据
 */
function compressedImage(path, obj, maxSize, callback) {
    let img = new Image();
    img.src = imgPath;
    img.onload = function () {
        const that = this;
        // 默认按比例压缩
        let w = that.width,
            h = that.height,
            scale = w / h;
        w = obj.width || w;
        h = obj.height && obj.height * (w / scale) || h;
        // 生成canvas
        let canvas = document.createElement('canvas');
        let ctx = canvas.getContext('2d');

        canvas.width = w;
        canvas.height = h;

        ctx.drawImage(that, 0, 0, w, h);
        // 图像质量,默认图片质量为0.8
        let quality = 0.8;
        if (obj.quality && obj.quality > 0 && obj.quality <= 1) {
            quality = obj.quality;
        }
        // quality值越小,所绘制出的图像越模糊
        let newBase64Image = canvas.toDataURL('image/jpeg', quality);

        let fileSize = getBase64ImageSize(newBase64Image);
        if (fileSize > maxSize && quality > 0.01) {
            if (quality > 0.05) {
                quality = quality - 0.05;
            } else {
                quality = 0.01;
            }
            compressedImage(imgPath, {
                quality: quality
            }, maxSize, callback);
            return;
        }

        // 回调函数返回压缩后的 base64图像
        callback(newBase64Image);
    }
}

三、使用 Canvas 和 Web Workers 实现图像压缩

JavaScript 的 Web Workers API 允许在浏览器中创建多个线程,可在后台线程执行 JavaScript 代码而不影响主线程的响应性。因此,Web Workers 适用于执行图像压缩等计算密集型任务。

以下是一个简单示例,展示如何使用 Web Workers 在后台线程执行图像压缩:

// 在主线程中
var worker = new Worker('worker.js');
worker.onmessage = function(e) {
    var compressedImage = e.data;
    // do something with compressedImage
};
worker.postMessage({
    image: base64Image,
    maxSize: 100 * 1024 // 最大文件大小为100KB
});
// worker.js
self.onmessage = function(e) {
    var image = e.data.image;
    var maxSize = e.data.maxSize;
    var img = new Image();
    img.src = image;
    img.onload = function() {
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        var width = img.width;
        var height = img.height;
        canvas.width = width;
        canvas.height = height;
        ctx.drawImage(img, 0, 0, width, height);
        var quality = 0.8;
        var resultBlob;
        do {
            canvas.toBlob(function(blob) {
                resultBlob = blob;
                self.postMessage(resultBlob);
            }, 'image/jpeg', quality);
            quality -= 0.1;
        } while (resultBlob.size > maxSize && quality > 0.1);
    }
};

在该示例中,主线程通过创建 Worker 对象并加载 worker.js 文件来启动后台线程。在 worker.js 中,通过 onmessage 定义图像压缩逻辑,并使用 postMessage 将压缩后的图像发送回主线程。此举将计算密集型任务移至后台,确保主线程响应性不受影响,避免页面卡顿或延迟。

需注意,Web Workers 无法直接访问 DOM,因此必须通过 postMessage 在主线程与后台线程之间传递数据。

这只是一个基础示例,实际应用中可能需要根据具体需求进行更多定制开发。

本文介绍了 JavaScript 实现图像压缩的方法,更多相关 JS 图像压缩内容可搜索本站往期文章或继续浏览后续相关文章,希望大家以后多多支持本站!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章