在线图片压缩工具核心JS实现

简介: 本项目为在线图片压缩工具,前端采用轻量状态模型支持多图批处理,完整实现“选择→读取→压缩→预览→下载”链路。核心包括:文件过滤与元信息补全、智能直出原图判定、可取消+防乱序的压缩请求、延迟重压缩调度,及资源自动回收机制。

这篇只讲本项目“图片压缩”工具的功能层 JavaScript 实现。整体链路是:

选择图片 -> 读取原图信息 -> 提交压缩参数 -> 获取压缩结果 -> 更新预览与统计 -> 下载

在线工具网址:https://see-tool.com/image-compressor
工具截图:
工具截图.png

1. 前端状态模型:围绕“多图批处理”设计

工具初始化后维护一个轻量状态对象,核心是 images 数组和当前预览索引。

const state = {
   
  images: [],
  currentIndex: 0,
  recompressTimer: null,
};

每张图片在内存里都是一个独立对象,既保存原图信息,也保存压缩结果信息:

  • 原图:originalUrloriginalSizeoriginalWidthoriginalHeightoriginalType
  • 压缩图:compressedUrlcompressedSizecompressedWidthcompressedHeightcompressedMimeType
  • 控制字段:compressControllercompressVersion

这种结构的好处是,单图更新不会影响其他图片,批量场景下逻辑更稳定。

2. 文件接入:先过滤,再补齐元信息

拖拽和文件选择最终都走同一入口 processFiles,先过滤非图片文件,再逐个处理。

const processFiles = async (files) => {
   
  const imageFiles = files.filter(
    (file) => file.type && file.type.startsWith("image/"),
  );
  if (imageFiles.length === 0) return;

  for (const file of imageFiles) {
   
    await addImageFile(file);
  }
};

addImageFile 会为文件创建对象 URL,并用 Image 对象读取像素尺寸,形成完整的图片对象后立即触发一次压缩。

const addImageFile = async (file) => {
   
  const url = URL.createObjectURL(file);
  const img = await loadImage(url);

  const imageObj = {
   
    id: `${
     Date.now()}-${
     Math.random()}`,
    name: file.name,
    file,
    originalUrl: url,
    originalIsObjectUrl: true,
    originalSize: file.size,
    originalType: file.type || "image/jpeg",
    originalWidth: img.width,
    originalHeight: img.height,
    compressedUrl: null,
    compressedSize: null,
    compressController: null,
    compressVersion: 0,
  };

  state.images.push(imageObj);
  state.currentIndex = state.images.length - 1;
  compressImage(imageObj);
};

3. 参数解析:输出格式和“直出原图”判定

压缩前先计算输出格式配置。工具支持 original/jpeg/png/webp/avif,并统一映射成 mimeType + extension

同时有一个关键分支:当用户选择 original 且质量 100,并且没有勾选移除元数据时,直接复用原图,不发请求。

const shouldUseOriginal = (imageObj) => {
   
  const format = elements.outputFormat.value;
  const quality = Number(elements.qualitySlider.value);
  if (format !== "original") return false;
  if (quality < 100) return false;
  if (elements.removeMetadata && elements.removeMetadata.checked) return false;
  return true;
};

这个分支能保证结果与用户设置一致:既然参数不要求二次编码,就直接返回原始文件。

4. 压缩主流程:可取消请求 + 版本号防乱序

compressImage 是核心函数,负责把当前图片和参数提交到接口并回写结果。

const formData = new FormData();
formData.append("image", imageObj.file, imageObj.name);
formData.append("format", elements.outputFormat.value);
formData.append("quality", String(Number(elements.qualitySlider.value)));
formData.append(
  "removeMetadata",
  String(Boolean(elements.removeMetadata?.checked)),
);
formData.append("progressive", String(Boolean(elements.progressive?.checked)));

const controller = new AbortController();
const compressVersion = Number(imageObj.compressVersion || 0) + 1;
imageObj.compressVersion = compressVersion;
imageObj.compressController = controller;

const response = await fetch("/api/image-compress", {
   
  method: "POST",
  body: formData,
  signal: controller.signal,
});

结果返回后不会立刻写入,而是先校验两件事:

  1. 这张图还在列表里(没被删除)
  2. 当前响应版本号仍是最新

只有通过校验才更新 compressedUrlcompressedSizecompressedWidthcompressedHeight

这能避免“用户连续拖动质量滑块”时旧请求覆盖新结果。

5. 重压缩触发:延迟调度统一入口

质量滑块、输出格式、元数据开关变化后,都不会直接逐张同步请求,而是进入 scheduleRecompress

const scheduleRecompress = (delay = 120) => {
   
  if (state.recompressTimer) {
   
    clearTimeout(state.recompressTimer);
    state.recompressTimer = null;
  }
  state.recompressTimer = setTimeout(() => {
   
    state.recompressTimer = null;
    updateCompressedImages();
  }, delay);
};

updateCompressedImages 内部遍历 state.images,逐张调用 compressImage,让参数变化后的行为保持一致。

6. 服务端压缩:字段校验 + Sharp 编码

接口只接收 POST multipart/form-data。先做参数清洗:

  • 文件体积上限(30MB)
  • 目标格式白名单
  • 质量范围(1~100)
  • 布尔参数标准化(true/false/1/0/yes/no

随后读取输入元信息,解析目标格式,再按格式进入不同编码分支:

switch (targetFormat) {
   
  case "jpeg":
    transformer = transformer.jpeg({
    quality, mozjpeg: true, progressive });
    break;
  case "png":
    transformer = transformer.png({
   
      quality,
      compressionLevel: 9,
      progressive,
    });
    break;
  case "webp":
    transformer = transformer.webp({
    quality, effort: 6 });
    break;
  case "avif":
    transformer = transformer.avif({
    quality, effort: 6 });
    break;
}

返回体是压缩后的二进制数据,同时附带输出信息头:

  • X-Output-Ext
  • X-Output-Width
  • X-Output-Height
  • X-Output-Size

前端据此展示压缩图信息,不需要再额外解析文件。

7. 结果展示与资源回收

统计区通过聚合 originalSizecompressedSize 计算总原始体积、总压缩体积、节省体积和压缩率。预览区按 currentIndex 展示当前图的原图/压缩图与像素信息。

批量下载按顺序触发,清空或删除图片时会执行两步清理:

  1. 中断进行中的压缩请求(AbortController
  2. 释放对象 URL(URL.revokeObjectURL

这样整条链路能长期稳定运行:上传、重压缩、预览切换、删除、清空都在同一套状态模型里闭环。

目录
相关文章
|
11天前
|
人工智能 弹性计算 安全
OpenClaw是什么?基础定义+功能场景+部署教程详细解读!
OpenClaw 是一款开源的、可自托管的 AI 智能体(Agent)平台,它让大语言模型(LLM)不再局限于对话框内的文字输出,而是能够直接操作你的电脑系统、执行真实世界任务。因其图标酷似龙虾,也被社区昵称为“龙虾助手”。
942 125
|
1月前
|
存储 自然语言处理 安全
MD5在线加密工具分享
一款基于Nuxt 3开发的MD5在线校验工具,支持文本(含Base64/Hex等格式)与文件(拖拽上传、本地分片计算)快速生成MD5摘要,输出可选Hex/Base64等格式并一键转大写。全程浏览器端处理,隐私安全,专为文件完整性校验设计。
560 2
|
10天前
|
机器学习/深度学习 人工智能 自然语言处理
视频去字幕工具横评:本地 AI、云端方案与传统方法的实战对比
做视频二创,最头疼的莫过于硬编码字幕。本文实测 5 种主流去字幕方案,从技术原理到实际效果,给你一份客观的选型指南。
250 6
|
11天前
|
存储 API Docker
告别“金鱼脑”!OpenClaw记忆系统完全手册(阿里云/本地部署+记忆优化+避坑指南)
“昨天聊完的需求,今天再问就忘;反复强调的偏好,每次都要重新说明”——这是2026年无数OpenClaw用户的痛点。参考文章精准指出核心问题:AI智能体的记忆能力直接决定使用体验,而OpenClaw的记忆系统并非“自动生效”,需要理解其底层逻辑才能充分利用。
1224 1
|
19天前
|
编解码 JavaScript
中文域名转码 在线工具分享
专为中文域名设计的在线转码工具!用Vue开发,无需安装,一键将中文域名与Punycode(xn--开头)互转。自动清理网址前缀,操作极简:输入→转换→复制。注册域名、配置网站、排查链接都好用!
141 12
|
1月前
|
运维 安全 JavaScript
证书信息查看 在线工具分享
这是一款基于Vue 3开发的轻量级在线工具——「证书信息查看」,无需安装、零门槛使用。支持输入域名、粘贴PEM证书或上传文件,秒级解析SSL/TLS证书关键信息(签发者、有效期、域名等),兼顾普通用户、站长与安全爱好者需求,全程本地处理,隐私无忧。
506 11
证书信息查看 在线工具分享
|
22天前
|
安全 JavaScript
文本字符数统计 在线工具分享
专为内容创作者设计的在线字数统计工具!支持实时统计中/英文、数字、空格等字符数,无需注册、不传数据,隐私安全。适配公众号、小红书、作业、简历等多场景,手机电脑即开即用。
366 7
|
25天前
|
JavaScript 测试技术 索引
正则表达式测试 在线工具分享
分享一款实用的在线正则表达式测试工具,支持实时匹配高亮、分组详情查看、g/i/m标志切换、常用模板一键插入及正则替换功能,助你高效验证、提取与处理文本,是开发与学习正则的得力助手!
261 10
|
1月前
|
JSON JavaScript 前端开发
Vue3项目JSON格式化工具技术实现详解
本文详解JSON格式化工具的前端实现,涵盖Composable核心逻辑(格式化、压缩、自动修复)与Vue交互优化(防抖预览、高亮动态加载、实时错误反馈),代码简洁高效,体验流畅。
387 15
Vue3项目JSON格式化工具技术实现详解
|
1月前
|
运维 前端开发 安全
文本差异对比器 在线工具分享
日常工作中常需对比文本/代码差异,肉眼识别易错低效。推荐我开发的在线工具——文本差异对比器,支持行/词/字符三级对比,红删绿增高亮显示,可忽略空格/大小写,纯前端运行,隐私安全,响应式设计,即开即用。
365 1