OpenClaw 的图片处理(resize、HEIC 转换、EXIF 旋转)支持两种后端:Sharp(C++ 原生模块)和 Sips(macOS 系统命令)。通过环境变量 OPENCLAW_IMAGE_BACKEND 控制选择。
切换方法
设置环境变量:
# 强制使用 sips(仅 macOS)
export OPENCLAW_IMAGE_BACKEND=sips
# 强制使用 sharp(所有平台)
export OPENCLAW_IMAGE_BACKEND=sharp
# 不设置:自动判断(macOS + Bun → sips,其他 → sharp)prefersSips() 逻辑(src/media/image-ops.ts:50):
function prefersSips(): boolean {
return (
process.env.OPENCLAW_IMAGE_BACKEND === "sips" || // 显式设置 sips
(process.env.OPENCLAW_IMAGE_BACKEND !== "sharp" && isBun() && process.platform === "darwin") // macOS + Bun 自动判断
);
}优先级:显式环境变量 > 平台自动判断。
Sharp vs Sips 对比
| 维度 | Sharp | Sips |
|---|---|---|
| 实现 | C++ 原生模块(libvips)+ Node bindings | macOS 系统命令(/usr/bin/sips) |
| 平台 | 跨平台(需安装对应平台原生二进制:@img/sharp-linux-arm64、@img/sharp-darwin-x64 等) | 仅 macOS |
| 依赖 | npm 包(sharp + optional dependencies @img/sharp-*) | 系统自带,零依赖 |
| 性能 | 高性能(C++ libvips),处理 4K 图片约 100-300ms | 中等(进程启动开销 + 处理),约 200-500ms |
| 功能 | resize、rotate、HEIC→JPEG、PNG alpha channel、PNG compression 精细控制 | resize、rotate、基础格式转换,不支持 PNG with alpha 精细控制、不支持 HEIC 输入 |
| 适用场景 | 生产环境、高性能处理、跨平台部署 | macOS 本地开发、快速验证、避免安装 sharp 依赖 |
| 失败处理 | 原生二进制缺失时抛错 → 图片被丢弃(见 read-tool 的 sanitization 章节) | macOS 上必定存在,不存在失败场景 |
功能边界差异
PNG with Alpha
resizeToPng(src/media/image-ops.ts:609)无 sips fallback:
export async function resizeToPng(params: { ... }): Promise<Buffer> {
await assertImagePixelLimit(params.buffer);
const ops = await loadMediaAttachmentImageOps(); // ← 必须走 sharp
return await ops.resizeToPng(params);
}原因:Sips 不支持 PNG alpha channel 的压缩级别精细控制。
HEIC 转换
convertHeicToJpeg(extensions/media-understanding-core/image-ops.ts)依赖 Sharp,Sips 不支持 HEIC 输入:
async convertHeicToJpeg(buffer: Buffer): Promise<Buffer> {
const sharp = await loadSharp(maxInputPixels);
return await sharp(buffer).jpeg({ quality: 90, mozjpeg: true }).toBuffer();
}src/media/image-ops.ts:568 的 fallback 尝试 macOS sips,但仅限于 macOS 平台:
export async function convertHeicToJpeg(buffer: Buffer): Promise<Buffer> {
await assertImagePixelLimit(buffer);
if (prefersSips()) {
return await sipsConvertToJpeg(buffer); // ← macOS 上尝试 sips
}
const ops = await loadMediaAttachmentImageOps();
try {
return await ops.convertHeicToJpeg(buffer);
} catch (error) {
if (process.platform !== "darwin") {
throw error; // ← 非 macOS,无 sips fallback,直接抛错
}
return await sipsConvertToJpeg(buffer); // ← macOS 上 fallback 到 sips
}
}JPEG Resize
resizeToJpeg(src/media/image-ops.ts:531)支持 sips fallback,但仅限 macOS:
export async function resizeToJpeg(params: { ... }): Promise<Buffer> {
await assertImagePixelLimit(params.buffer);
if (prefersSips()) {
const normalized = await normalizeExifOrientationSips(params.buffer);
// ... sips resize logic ...
return await sipsResizeToJpeg({ buffer: normalized, ... });
}
const ops = await loadMediaAttachmentImageOps();
return await ops.resizeToJpeg(params);
}失败处理机制
Sharp 失败时(如原生二进制缺失),在 src/agents/tool-images.ts 的 sanitizeContentBlocksImages 中:
try {
const resized = await resizeImageBase64IfNeeded({ ... });
out.push({ ...block, data: resized.base64, mimeType: resized.mimeType });
} catch (err) {
out.push({
type: "text",
text: `[${label}] omitted image payload: ${String(err)}`,
}); // ← 图片被替换为错误文本
}LLM 收到错误文本而非图片内容,无法进行视觉理解。
相关案例:notes/sharp-linux-arm64-missing — linux-arm64 上 sharp 原生二进制缺失导致图片被丢弃。
推荐策略
Linux 环境(包括 linux-arm64):
- 必须用 Sharp(Sips 不存在)
- 确保安装对应平台原生二进制(见 notes/sharp-linux-arm64-missing)
macOS 环境:
- 本地开发可用 Sips(
OPENCLAW_IMAGE_BACKEND=sips),避免安装 Sharp 依赖 - 生产环境仍推荐 Sharp(性能更好、跨平台一致)
- 需处理 PNG with alpha 或 HEIC 时,必须用 Sharp
通用建议:
- 不要在代码中强制用 sips(
prefersSips已是懒加载 fallback) - 遇到 Sharp 安装问题时,优先解决 Sharp 安装而非降级到 sips(Linux 上不适用)
- macOS 上如需快速验证可临时切 sips,但长期仍用 Sharp
相关
- read-tool — Read 工具中图片 sanitization 调用链
- src/media/image-ops — 图片处理核心逻辑(resizeToJpeg、getImageMetadata、HEIC 转换)
- notes/sharp-linux-arm64-missing — Sharp 原生二进制缺失的实际案例
- tool-image-generation — 图片生成工具(不涉及 resize)