Bun设计的API一直都是简单, 优雅
bash
import { Image } from 'bun'; // 全局可用,无需导入
// 最简示例
await Bun.file('photo.jpg')
.image()
.resize(800, 600)
.webp({ quality: 80 })
.write('thumb.webp');
为什么换掉 sharp?
sharp 是 Node.js 最流行的图片库,但安装痛苦,需要编译原生模块、CI 经常失败。
bash
# sharp 的日常
npm install sharp # 可能失败,Alpine 需要 apk add vips-dev
# CI 缓存频繁失效
Bun.Image 是什么?
Bun v1.3.14+ 内置的链式图像处理 API,用 Zig 实现,编译进 Bun 二进制文件。输入灵活,输出多样,支持 JPEG/PNG/WebP 等主流格式,性能接近或超过 sharp。
bash
import { Image } from 'bun'; // 全局可用,无需导入
// 最简示例
await Bun.file('photo.jpg')
.image()
.resize(800, 600)
.webp({ quality: 80 })
.write('thumb.webp');
输入源:文件、Buffer、Blob 都行
你可以直接传入文件路径、ArrayBuffer、TypedArray、Blob、BunFile 甚至 data: URL。所有输入都是零拷贝设计,避免不必要的内存复制。
bash
// 文件路径
Bun.file('input.jpg').image()
// Buffer / ArrayBuffer(零拷贝)
const buffer = await fetch(url).arrayBuffer();
new Image(buffer).resize(200).jpeg()
// Blob / BunFile
const blob = new Blob([data], { type: 'image/png' });
new Image(blob).png().write('out.png')
输出方式:Buffer/Blob/Response 随意选
处理完的图片可以写入文件、转为 Buffer、生成 Base64,甚至可以当作 Response body 直接返回(自动设置 Content-Type)。
bash
const img = Bun.file('test.jpg').image().resize(300);
await img.write('out.jpg'); // 写文件
const buf = await img.buffer(); // ArrayBuffer
const bytes = await img.bytes(); // Uint8Array
const b64 = await img.toBase64(); // Base64 字符串
// 直接返回 HTTP 响应
return new Response(await img.jpeg());
链式变换:缩放、旋转、调色
Bun.Image 提供了和 sharp 类似的链式 API:resize、rotate(90的倍数)、flip/flop、modulate(亮度/饱和度)。每个操作都返回新实例,不修改原图。
bash
Bun.file('in.png')
.image()
.resize(800, null, { fit: 'cover', withoutEnlargement: true })
.flip() // 垂直翻转
.rotate(90) // 仅支持 90/180/270
.modulate({ brightness: 1.2, saturation: 0.8 })
.webp({ quality: 80 })
.write('out.webp');
格式支持矩阵
解码:所有平台都支持 JPEG/PNG/WebP/GIF(静态)/BMP;macOS/Windows 额外支持 HEIC/AVIF/TIFF。编码:JPEG/PNG/WebP 全平台;HEIC/AVIF 仅 macOS/Windows;BMP/TIFF/GIF 不支持编码。
| 格式 | 解码 | 编码 | 备注 | | :-- | :-- | :-- | :-- | | JPEG | ✅ | ✅ | | | PNG | ✅ | ✅ | | | WebP | ✅ | ✅ | | | GIF | ✅ | ❌ | 仅静态帧 | | BMP | ✅ | ❌ | | | HEIC | ✅* | ✅* | *macOS/Windows | | AVIF | ✅* | ✅* | *macOS/Windows |
性能亮点:metadata 快 70 倍
sharp 的 metadata() 需要完整解码图像才能拿到宽高,而 Bun.Image 只读取文件头部几百字节就直接返回。缩放操作两者持平,但 Bun.Image 内存占用更低(约-40%)。
bash
// metadata 对比
// sharp: 读取整张 4K 图片(~10MB)
const meta = await sharp('4k.jpg').metadata(); // ~21ms
// Bun.Image: 只读头部
const meta = await Bun.file('4k.jpg').image().metadata(); // ~0.3ms
// 缩放性能(4K→1080p):Bun.Image 快约 10-20%
// 并发 50 任务:sharp 160ms,Bun.Image 约 130ms
从 sharp 迁移:四步替换
第一步替换构造函数;第二步把 .toFormat('webp') 改为 .webp();第三步注意 metadata 要先 .image();第四步调整输出方法(.toBuffer() → .buffer())。
bash
// Before (sharp)
import sharp from 'sharp';
const out = await sharp('in.jpg')
.resize(800)
.toFormat('webp')
.toBuffer();
// After (Bun.Image)
const out = await Bun.file('in.jpg')
.image()
.resize(800)
.webp() // 格式方法作为 pipeline 终点
.buffer();
// metadata 迁移
// sharp: await sharp(buf).metadata()
// Bun.Image: await Bun.file(buf).image().metadata()
局限性:不是所有 sharp 功能都有
Bun.Image 目前不支持文本叠加、SVG 渲染、任意角度旋转(仅 90 倍数)、复杂裁剪路径、GIF 动画、多页 TIFF,以及 BMP/TIFF/GIF 的编码。Linux 上也不支持 HEIC/AVIF 解码。
bash
// ❌ 这些暂不支持
// - 文本水印 / SVG 绘图
// - .rotate(45) 任意角度
// - .composite([...])
// - GIF 动画编码
// - Linux 上读取 HEIC
// ✅ 90% 场景够用:缩略图、格式转换、质量压缩、元数据
结论:大多数项目可以直接换
如果你只需要缩略图、格式互转、质量压缩、快速获取宽高,Bun.Image 零依赖、更快、更省内存。只有遇到文本水印、任意旋转、专业摄影流程时才需要保留 sharp。
bash
// 推荐方案:Bun.Image 主力,sharp 兜底
const useSharp = needTextOverlay || needFreeRotate;
if (!useSharp) {
await Bun.file('input').image().resize(200).webp().write('out.webp');
} else {
await sharp('input').resize(200).webp().toFile('out.webp');
}