| name | image-compressor |
| description | 高性能图片压缩 API 服务。支持 bmp/gif/heic/jfif/jpeg/jpg/livp/png/ppm/tif/tiff/webp 格式,可设置目标文件大小自动迭代压缩。提供 HTTP API 接口供 Java 后端调用,支持高并发、低内存占用。使用场景:图片批量压缩、Web 图片优化、移动端图片上传预处理、存储空间优化。 |
图片压缩技能
快速开始
1. 安装依赖
cd /home/admin/.openclaw/workspace/skills/image-compressor/scripts
pip3 install -r requirements.txt
2. 启动服务
./start.sh
python3 server.py
默认监听 http://0.0.0.0:8765
3. API 文档
启动后访问:
- Swagger UI:
http://localhost:8765/docs
- ReDoc:
http://localhost:8765/redoc
API 接口
方式 1: 上传文件压缩
curl -X POST "http://localhost:8765/compress" \
-F "file=@image.jpg" \
-F "quality=80" \
-F "max_size_kb=500" \
-o compressed.jpg
参数:
file: 图片文件 (必填)
quality: 压缩质量 1-100 (默认 85)
max_size_kb: 目标文件大小 KB (可选,自动迭代压缩)
max_width: 最大宽度 (可选)
max_height: 最大高度 (可选)
output_format: 输出格式 (可选,默认保持原格式)
方式 2: URL 图片压缩
curl -X POST "http://localhost:8765/compress/url" \
-F "url=https://example.com/image.jpg" \
-F "quality=80" \
-F "max_size_kb=500"
curl -X POST "http://localhost:8765/compress/url/json" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/image.jpg",
"quality": 80,
"max_size_kb": 500,
"max_width": 1920,
"output_format": "WEBP"
}'
JSON 参数:
url: 图片 URL 地址 (必填)
quality: 压缩质量 1-100 (默认 85)
max_size_kb: 目标文件大小 KB (可选)
max_width/max_height: 最大尺寸限制 (可选)
output_format: 输出格式 (可选)
方式 3: Base64 图片压缩
curl -X POST "http://localhost:8765/compress/base64" \
-H "Content-Type: application/json" \
-d '{
"image_base64": "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
"filename": "photo.jpg",
"quality": 75,
"max_size_kb": 300,
"output_format": "WEBP"
}'
JSON 参数:
image_base64: Base64 编码的图片数据 (必填,可带或不带 data:image/...;base64, 前缀)
filename: 文件名,用于推断格式 (默认 image.jpg)
quality: 压缩质量 1-100 (默认 85)
max_size_kb: 目标文件大小 KB (可选)
max_width/max_height: 最大尺寸限制 (可选)
output_format: 输出格式 (可选)
响应:
{
"success": true,
"file_id": "uuid-string",
"original_size": 2048576,
"compressed_size": 512000,
"compression_ratio": "25.0%",
"format": "WEBP",
"width": 1920,
"height": 1080,
"elapsed_ms": 156.23
}
响应头:
X-Original-Size: 原始大小 (字节)
X-Compressed-Size: 压缩后大小 (字节)
X-Compression-Ratio: 压缩率
X-Elapsed-Ms: 耗时 (毫秒)
Java 调用示例
文件上传压缩
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", "image.jpg",
RequestBody.create(file, MediaType.parse("image/jpeg")))
.addFormDataPart("quality", "80")
.addFormDataPart("max_size_kb", "500")
.build();
Request request = new Request.Builder()
.url("http://localhost:8765/compress")
.post(requestBody)
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
byte[] compressedData = response.body().bytes();
String ratio = response.header("X-Compression-Ratio");
System.out.println("压缩率:" + ratio);
}
}
URL 图片压缩
ObjectMapper mapper = new ObjectMapper();
ObjectNode params = mapper.createObjectNode();
params.put("url", "https://example.com/image.jpg");
params.put("quality", 80);
params.put("max_size_kb", 500);
params.put("output_format", "WEBP");
RequestBody body = RequestBody.create(
params.toString(),
MediaType.parse("application/json")
);
Request request = new Request.Builder()
.url("http://localhost:8765/compress/url/json")
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
String json = response.body().string();
CompressResult result = mapper.readValue(json, CompressResult.class);
System.out.println("压缩率:" + result.compressionRatio);
}
}
Base64 图片压缩
String base64Data = "data:image/jpeg;base64,/9j/4AAQSkZJRg...";
ObjectNode params = mapper.createObjectNode();
params.put("image_base64", base64Data);
params.put("filename", "photo.jpg");
params.put("quality", 75);
params.put("max_size_kb", 300);
params.put("output_format", "WEBP");
RequestBody body = RequestBody.create(
params.toString(),
MediaType.parse("application/json")
);
Request request = new Request.Builder()
.url("http://localhost:8765/compress/base64")
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
String json = response.body().string();
CompressResult result = mapper.readValue(json, CompressResult.class);
System.out.println("压缩完成:" + result.compressionRatio);
}
}
Spring Boot 示例
@Service
public class ImageCompressorService {
@Value("${image.compressor.url:http://localhost:8765}")
private String compressorUrl;
private final RestTemplate restTemplate = new RestTemplate();
public byte[] compressImage(MultipartFile file, int quality, Integer maxSizeKb) {
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file", file.getResource());
body.add("quality", String.valueOf(quality));
if (maxSizeKb != null) {
body.add("max_size_kb", String.valueOf(maxSizeKb));
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(body, headers);
ResponseEntity<byte[]> response = restTemplate.postForEntity(
compressorUrl + "/compress",
request,
byte[].class
);
if (response.getStatusCode().is2xxSuccessful()) {
return response.getBody();
}
throw new RuntimeException("图片压缩失败");
}
}
批量压缩
curl -X POST "http://localhost:8765/compress/batch" \
-F "files=@image1.jpg" \
-F "files=@image2.png" \
-F "files=@image3.webp" \
-F "quality=75" \
-F "max_size_kb=300" \
-o compressed.zip
返回 ZIP 文件,包含所有压缩后的图片。
从 URL 压缩
curl -X POST "http://localhost:8765/compress/url" \
-F "url=https://example.com/image.jpg" \
-F "quality=80" \
-F "max_size_kb=500"
配置选项
环境变量
| 变量 | 默认值 | 说明 |
|---|
HOST | 0.0.0.0 | 监听地址 |
PORT | 8765 | 监听端口 |
WORKERS | 4 | Uvicorn 工作进程数 |
MAX_WORKERS | 8 | 压缩线程池大小 |
性能调优
高并发场景:
WORKERS=8 MAX_WORKERS=16 ./start.sh
低内存场景:
WORKERS=2 MAX_WORKERS=4 ./start.sh
生产环境部署:
[Unit]
Description=Image Compressor API
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/home/admin/.openclaw/workspace/skills/image-compressor/scripts
Environment=HOST=0.0.0.0
Environment=PORT=8765
Environment=WORKERS=4
Environment=MAX_WORKERS=8
ExecStart=/usr/bin/python3 -m uvicorn server:app --host 0.0.0.0 --port 8765 --workers 4
Restart=always
[Install]
WantedBy=multi-user.target
支持格式
| 格式 | 扩展名 | 压缩支持 | 目标大小控制 |
|---|
| JPEG | .jpg, .jpeg, .jfif | ✅ | ✅ |
| PNG | .png | ✅ | ✅ |
| WebP | .webp | ✅ | ✅ |
| GIF | .gif | ✅ | ✅ |
| TIFF | .tif, .tiff | ✅ | ✅ |
| BMP | .bmp | ✅ | ✅ |
| HEIC | .heic, .heif | ✅ | ✅ |
| PPM | .ppm | ✅ | ✅ |
| LIVP | .livp | ✅ | ✅ |
核心特性
1. 目标大小控制
设置 max_size_kb 后,服务会自动迭代压缩直到达到目标大小:
- 逐步降低质量参数
- 必要时缩小尺寸
- 保持可接受的视觉质量
2. 高并发处理
- 异步 I/O (FastAPI + uvicorn)
- 线程池并行压缩
- 支持水平扩展 (多实例 + 负载均衡)
3. 低内存占用
- 流式处理大文件
- 单图内存限制 (默认 256MB)
- 及时释放资源
4. 安全特性
- 文件格式验证
- 文件大小限制
- CORS 配置 (可限制域名)
性能基准
测试环境:8 核 CPU, 16GB RAM
| 场景 | 并发数 | 平均耗时 | 吞吐量 |
|---|
| 单图压缩 (2MB JPEG) | 1 | ~150ms | - |
| 批量压缩 | 10 | ~200ms | 50 张/秒 |
| 高并发 | 100 | ~500ms | 200 张/秒 |
故障排除
依赖安装失败
pip3 install --upgrade pip
pip3 cache purge
pip3 install -r requirements.txt --no-cache-dir
HEIC 格式不支持
pip3 install pillow-heif
python3 -c "import pillow_heif; print(pillow_heif.__version__)"
端口被占用
lsof -i :8765
PORT=8766 ./start.sh
压缩后文件过大
- 降低
quality 参数
- 设置
max_size_kb 让服务自动处理
- 检查原图是否已经是高压缩格式
相关文件
scripts/image_compressor.py - 核心压缩库
scripts/server.py - FastAPI 服务
scripts/start.sh - 启动脚本
scripts/requirements.txt - Python 依赖