前端图片压缩库 Compressor.js 使用指南

在现代 Web 应用中,图片往往是造成页面体积大的主要元凶。尤其在用户上传图片(头像、相册、商品图等)时,如果不做处理,一张高分辨率的照片可能达到几 MB,直接上传不仅费流量,还可能造成服务器压力、慢速网络下体验差。

因此,将图片在客户端预处理(压缩、缩放、重编码)已成为常见做法。Compressor.js 就是一个轻量、易用的前端图片压缩库,适合在浏览器端对用户上传的图片进行压缩。下面我们来深入了解它。

什么是 Compressor.js

Compressor.js 是一个在浏览器端运行的 JavaScript 图片压缩库。它利用 HTMLCanvasElement 的 toBlob / toDataURL 方法对图片进行“有损压缩(lossy compression)”,即在保证可接受画质的前提下减小文件体积。

该库支持对 JPEG / PNG / WebP 等常见图片格式进行压缩,还提供对尺寸约束、比例控制、旋转方向校正(EXIF 方向)等选项。

特点包括:

  • 支持直接传入 File 或 Blob 对象进行压缩
  • 压缩过程是异步的,使用回调或 Promise 风格处理
  • 支持设置质量(quality)、最大/最小宽高(maxWidth、maxHeight、minWidth、minHeight)、是否保持 EXIF 信息(retainExif)、方向检测(checkOrientation)等
  • 可配置“严格模式”(strict),即若压缩后的文件比原图还大,则返回原图而非压缩结果

Compressor.js 的官方版本发布在 GitHub,并以 MIT 协议开源。

Compressor.js 核心 API 与配置项

构造 API

new Compressor(fileOrBlob, options)
  • fileOrBlob:必选。即待压缩的 File 或 Blob 对象
  • options:可选。用于配置压缩行为的参数对象

常用配置项说明(部分)

在使用 new Compressor(file, options) 时,你可以给 options 对象传入多个配置项来控制压缩行为。这里列出几项常见并且实用的配置,以及它们的作用和默认值(若有):

  • strict(布尔值,默认 true):如果压缩后的文件比原图更大,开启 strict 模式后会返回原图而不是压缩结果。但在某些情形下(比如 retainExif = true、指定了不同的 mimeType、输出尺寸大于原图、或 maxWidth/maxHeight 限制小于原图尺寸等)这个回退机制会被忽略。
  • checkOrientation(布尔值,默认 true):表示是否读取 JPEG 图片的 EXIF 方向信息,并自动对图片进行旋转或翻转校正,以避免手机拍照方向错误的问题。对于非常大的文件(如大于 10 MB),有时建议禁用它以防内存崩溃。
  • retainExif(布尔值,默认 false):压缩后是否保留原始图片的 EXIF 元数据(如相机型号、拍照时间、地理位置信息等)。保留 EXIF 会使压缩后体积略增,一般在业务有强烈需求才启用。
  • maxWidth / maxHeight(数字型,默认分别为 Infinity):用来限制压缩后图片的最大宽度和最大高度。如果原图某一方向超过这个值,则会按比例缩放至该上限以内。
  • minWidth / minHeight(数字型,默认分别为 0):设置压缩后图片的最小宽度和最小高度,下限通常用于避免压缩结果小得不可用。注意 minWidth/minHeight 不应超过 maxWidth/maxHeight。
  • width / height(数字型,可选):如果你给定了输出的明确宽或高,Compressor 会尝试把图片缩放到这个尺寸(在保持比例或裁剪规则下)。如果你只指定一个维度,另一维度会根据原始宽高比自动计算。
  • resize(字符串,可选值 “none”/“contain”/“cover”,默认 “none”):指定当同时设置 width 和 height 时,图片如何适应目标尺寸。比如 “contain” 表示缩放以保证整张图片都能显示在目标框内,“cover” 表示缩放/裁剪以填满目标框。若不设置 width/height,这个选项不会生效。
  • quality(数字型,0 到 1 之间,默认约为 0.8):用于控制输出 JPEG 或 WebP 图片的压缩质量(越小体积越小但画质下降越明显)。如果该值设置为 1,有时可能使输出比原图还大。
  • mimeType(字符串,默认 “auto”):指定输出图片的 MIME 类型,比如 “image/jpeg”、“image/png” 或 “image/webp”。默认情况下会沿用原图的类型(或根据浏览器能力决定)。需要注意的是在某些浏览器里把 PNG 转为 WebP 可能不被支持。
  • convertTypes(字符串或字符串数组,默认 ["image/png"]):指明哪类图片类型(如 “image/png”)在超过某个大小阈值时要转换为其它格式(如 JPEG)。
  • convertSize(数字型,默认值约 5 MB):如果图片的类型在 convertTypes 列表中,并且文件大小超过这个阈值,就会触发格式转换(比如把 PNG 转为 JPEG)。若你不希望任何类型发生转换,可将其设为 Infinity。
  • beforeDraw(context, canvas)(函数,可选):在把图片绘制到 Canvas 之前会调用这个钩子,你可以在这里做一些背景填充、滤镜预处理等操作。参数包括 Canvas 的 2D 上下文 context 和 canvas 本身。
  • drew(context, canvas)(函数,可选):在图片绘制到 Canvas 之后会调用这个钩子,适合用于添加水印、文字提示、边框等后处理操作。
  • success(result)(函数,必选/回调):当压缩成功时会调用此回调,result 是输出的 Blob 或 File 对象。你可以在这里拿到压缩后的图片用于上传或展示。
  • error(err)(函数,回调):若在压缩过程中出现错误(例如资源不足、浏览器不支持、图片加载失败等),会调用这个回调,err 为错误对象。

这些配置项组合起来,可以灵活地控制压缩后的图片在质量、尺寸、格式、方向、元数据等方面的表现。根据不同业务场景(如用户头像、商品图、相册上传等),你可以选择性开启或调整这些参数,以在文件体积和可用画质之间达到最优平衡。

注意:Compressor.js 默认行为包含“有损压缩 + 异步处理”,它不会无损压缩或保证完全保真。

Promise 风格封装

由于 new Compressor(...) 本身使用回调风格处理,一般我们会以 Promise 包装它,方便在现代 async/await 语法中使用:

function compressImage(file, options = {}) {
  return new Promise((resolve, reject) => {
    new Compressor(file, {
      ...options,
      success(result) {
        resolve(result);
      },
      error(err) {
        reject(err);
      }
    });
  });
}

这样就可以:

const compressed = await compressImage(file, { quality: 0.7, maxWidth: 1200, maxHeight: 1200 });
// compressed 是 Blob / File

Compressor.js 的使用代码示例

下面是一个比较完整的前端压缩 + 上传示例,适用于常见场景(如用户选择文件后自动压缩然后通过 AJAX 上传):

<input type="file" id="inputFile" accept="image/*">

<script type="module">
  import Compressor from 'compressorjs';

  document.getElementById('inputFile').addEventListener('change', async (e) => {
    const file = e.target.files[0];
    if (!file) return;

    try {
      const compressedBlob = await new Promise((resolve, reject) => {
        new Compressor(file, {
          quality: 0.6,
          maxWidth: 1600,
          maxHeight: 1600,
          checkOrientation: true,
          convertSize: 200 * 1024, // 小于 200 KB 的图片不转换格式
          success(result) {
            resolve(result);
          },
          error(err) {
            reject(err);
          }
        });
      });

      const formData = new FormData();
      // 第三个参数用于指定文件名,否则部分后端不识别
      formData.append('image', compressedBlob, file.name);

      // 使用 fetch 或 axios 上传
      const resp = await fetch('/api/upload', {
        method: 'POST',
        body: formData
      });
      console.log('Upload success', resp);

    } catch (err) {
      console.error('Compression failed:', err.message);
    }
  });
</script>

如果你在无 Ajax 的传统表单提交场景中使用,需要将压缩后图片转为 Base64 或用隐藏 input[type="hidden"] 存储后提交。示例(jQuery 风格):

$('#file').change(function(e) {
  const file = e.target.files[0];
  new Compressor(file, {
    quality: 0.8,
    maxWidth: 1600,
    maxHeight: 1600,
    success(result) {
      const reader = new FileReader();
      reader.readAsDataURL(result);
      reader.onloadend = function() {
        $('#hiddenImageField').val(reader.result); // hidden input name 同服务端字段
      };
    },
    error(err) {
      console.error(err.message);
    }
  });
});

服务端收到 Base64 字符串后再解码存储即可。

在现代框架(React / Vue / Angular)中,也可将上述逻辑包裹为 Hook / 组合函数 / 服务,便于在组件里使用。

性能与画质考量

在使用 Compressor.js 时,有几个关键点需要权衡与注意:

  • 压缩质量 vs 体积:quality 值是压缩最直接的调控杠杆,越低体积越小,但画质下降越明显。一般范围可设在 0.5 ~ 0.8 之间,具体视图片内容和用户场景而定。
  • 尺寸控制比压缩更有效:对于非常高分辨率图片(如手机拍照的几千像素),首先将其缩放至合理宽高(如最大边 1600、2000 px)比单纯用质量压缩更能节省体积且画质损失小。
  • 严格模式(strict):若压缩后体积比原图反而大(可能在图片已很小或复杂纹理时发生),启用 strict 模式可优雅地回退到原图,避免“压缩反而更重”的尴尬。
  • EXIF 方向修正:对于用户用手机拍照的图片,常常存在 EXIF 方向信息(横拍/竖拍方向),checkOrientation 设置为 true 可以自动修正。若不修正,可能出现图片旋转错误。
  • 保留 EXIF 元数据:若业务场景需要保留 EXIF(如拍照时间、地理位置、相机型号等),启用 retainExif。但这会增加输出体积,应谨慎使用。
  • 异步处理 & 卡顿风险:虽然压缩是异步的,但对大图(如几 MB 的图片)仍可能在主线程消耗一定时间。可以考虑将压缩任务放在 requestIdleCallback 或 Web Worker(如果你自己封装)中,以避免界面卡顿。
  • 浏览器兼容性:Compressor.js 基于 Canvas + Blob API 实现,因此在现代浏览器中支持良好,但在极老旧环境可能需要兼容处理。

实战优化建议与注意事项

  • 批量压缩时建议串行或分批:一次压缩大量高分辨率图片可能造成内存或性能异常。可做“队列 + 延时”处理。
  • 根据文件大小动态调整策略:对于小图(如几 KB / 几十 KB),可以不压缩或只做尺寸调整;对于大图才做较激进压缩。
  • 进度或用户提示:如果压缩时间较长,提供进度提示或“处理中”状态,以提升用户感知体验。
  • SDK 封装 / 封装成服务:将压缩逻辑抽象为通用工具 / SDK(支持参数配置、错误捕获、重试、超时机制等)更便于复用。
  • 后端校验与降级:即便前端压缩,也应在后端对上传图片做尺寸、格式、体积校验,以防用户绕过前端提交超大文件。
  • 渐进增强 / 兼容降级:对于不支持 Blob / Canvas API 的旧设备,提供降级方案(例如不压缩上传或服务器端压缩)。
  • 可结合 CDN / 图片处理服务二次优化:将预压缩 + 服务端 / CDN 端处理结合起来,达到更高压缩比和加载性能。

总结

Compressor.js 是一个轻量、使用简单、功能实用的前端图片压缩工具。通过合理选择 quality 与尺寸参数,并辅以异步处理和用户体验设计,你可以在用户上传环节截断大图流量,显著提升应用性能和用户体验。

在实际项目中,建议将其封装为可配置的工具模块/服务,并配合后端校验与 CDN 图像服务共同构建高效的图片处理链路。只要把握好“画质 vs 体积 vs 性能”的折中,就能在压缩与体验之间做到较优平衡。

评论