用纯浏览器实现「图片压缩」:不上传服务器、批量压缩、支持 PNG/JPEG/WebP(imgism.cn)
最近做了一个纯前端的在线工具站「一米集 / imgism.cn」,其中我最常用、也最想优先打磨的功能就是:图片压缩。
很多时候我们只想把图片体积缩小一点(发微信、发邮件、上传到后台、放到文档里),但又不想把图片上传到陌生网站。于是我做了一个完全在浏览器本地完成压缩的小工具:上传图片后在前端用 Canvas 重新编码输出,整个过程不经过服务器。
本文会介绍网站整体信息与功能结构,并重点讲讲这个“纯浏览器图片压缩”的实现思路和使用方式。
网站是什么:一米集(imgism.cn)
一米集是一个纯静态站点(部署在 Cloudflare Pages),主打“打开即用、无需安装、尽量本地处理”的在线工具集合。
目前网站按分类提供:
- 图片工具:压缩、裁剪、尺寸调整、旋转/翻转、格式转换、拼接、EXIF 查看/删除、图片↔Base64、OCR、抠图去背景、文字水印、图层合成、二维码生成、颜色提取等
- PDF 工具:合并、拆分、提取页面、删除页面、PDF 转图片等
- 文本工具:文本对比、文本文件对比、文本去重、字符统计、文本分析器(阅读/朗读时间、关键词密度等)
- JSON 工具:格式化、压缩/转义、Diff、键排序等
- 其他工具:计算器、正则测试、条码生成、年龄计算器、BMI 计算器、IP 信息查询等
网站首页入口:
图片压缩工具入口:
核心功能:纯浏览器图片压缩(不上传服务器)
这次重点介绍的工具是「图片压缩」:批量压缩并导出 PNG/JPEG/WebP,并支持打包下载。
它做了几件我自己很在意的事:
1)批量上传 + 预览
- 支持拖拽多张图片上传,或者点击选择文件
- 左侧显示图片列表(文件名、分辨率、原始体积)
- 中间区域用 Canvas 做预览(预览会按最大边 720 做缩放,不影响最终导出)
2)输出格式可选:JPEG / PNG / WebP
- JPEG:适合照片/大图,体积通常更小
- PNG:更适合需要透明通道的图(logo/图标等),压缩幅度一般不如 JPEG/WebP
- WebP:很多场景下兼顾体积与质量
另外我在工具里做了一个明确提示:
- 转 JPEG 时,如果原图有透明背景,会使用白底合成(这是 JPEG 格式本身不支持透明导致的)
- 需要保留透明背景,建议导出 PNG 或 WebP
3)质量可调(对 JPEG / WebP 生效)
质量范围 1~100。PNG 是无损重编码,所以质量参数不会生效(工具里也会做 UI 降亮与提示)。
4)下载方式:单张下载 + ZIP 打包下载
- 每张图压缩后会显示“原始体积 → 压缩后体积 + 节省比例”
- 支持单张下载
- 支持把所有结果打包成 ZIP 一键下载(前端使用 JSZip)
怎么用:3 步完成压缩
- 打开图片压缩页:imgism.cn/tools/image…
- 拖拽/选择图片(可多张)
- 选择输出格式,必要时调整质量(JPEG/WebP),点击“压缩”,然后下载单张或 ZIP
隐私与安全:为什么说“不上传服务器”
这个工具的核心逻辑是:
- 图片读取:
FileReader在浏览器中把文件读成 DataURL - 图片解码:
new Image()加载 DataURL 得到像素数据 - 压缩导出:
Canvas.drawImage()后用canvas.toBlob()重新编码成指定格式 - 下载:用
URL.createObjectURL(blob)生成临时链接并触发下载
整个过程都发生在你的浏览器里,不需要把图片发送到服务端处理。
实现思路(前端版):Canvas + toBlob 重新编码
下面用一段“思路级”的伪代码描述实现流程(与实际代码结构一致):
// 1) 读取本地文件 -> Image
const img = await readFileAsImage(file); // FileReader + new Image()
// 2) draw 到 canvas
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
// 3) 根据格式导出 blob
const mime = fmt === 'jpeg' ? 'image/jpeg'
: fmt === 'webp' ? 'image/webp'
: 'image/png';
const quality = fmt === 'jpeg' || fmt === 'webp'
? sliderValue / 100
: undefined; // PNG 无损
const blob = await new Promise(resolve => {
canvas.toBlob(resolve, mime, quality);
});
// 4) 下载(单张)
const url = URL.createObjectURL(blob);
download(url, filename);
URL.revokeObjectURL(url);
如果选择导出 JPEG,我会先铺一层白底(避免透明区域变成黑底/异常):
if (fmt === 'jpeg') {
ctx.fillStyle = '#fff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
ctx.drawImage(img, 0, 0);
批量 ZIP 下载则是把每张 blob 放进 zip:
const zip = new JSZip();
zip.file('a.webp', blobA);
zip.file('b.webp', blobB);
const out = await zip.generateAsync({ type: 'blob' });
适用场景
- 需要把图片发微信/邮件,但体积太大
- 网站上传/后台上传限制大小
- 想做页面性能优化(图片体积直接影响首屏速度)
- 处理包含敏感信息的图片,不希望上传到第三方服务器
后续计划
接下来我准备继续把图片工具做得更“顺手”,例如:
- 更清晰的压缩参数建议(按分辨率/内容类型推荐质量)
- 更多下载命名规则/批量重命名
- 处理 EXIF 的“保留/删除”选项与压缩联动
如果你也经常用图片压缩,欢迎试用并给我反馈(我会优先补齐大家最常用的流程)。
相关链接
- 工具站首页:imgism.cn/
- 图片压缩:imgism.cn/tools/image…