Bitmap Vector Studio v2.0 提供基于 FastAPI 的 RESTful API,支持同步/异步位图转矢量转换、批量任务、预设查询和智能推荐。
v1.1 新增:桌面应用通过 Tauri Command 桥接 Python 后端,提供与 Web API 等价的功能。详见 docs/DESKTOP.md。
# 默认启动(127.0.0.1:8000)
vector-studio api
# 指定主机和端口
vector-studio api --host 0.0.0.0 --port 8000
# 指定工作进程数
vector-studio api --host 0.0.0.0 --port 8000 --workers 4docker run -d -p 8000:8000 jammyfu/bitmap-vector-studiodocker-compose up -d vector-studio服务启动后,访问 http://localhost:8000/health 验证运行状态。
| 端点 | 方法 | 说明 | 请求类型 |
|---|---|---|---|
/health |
GET | 健康检查 | - |
/presets |
GET | 列出所有内置预设 | - |
/convert |
POST | 同步转换,直接返回 SVG 文件 | multipart/form-data |
/convert/async |
POST | 异步转换,返回任务 ID | multipart/form-data |
/status/{task_id} |
GET | 查询异步任务状态 | - |
/download/{task_id}/{format} |
GET | 下载已完成任务的结果 | - |
/recommend |
POST | 上传图片获取智能预设推荐 | multipart/form-data |
/batch |
POST | 批量异步转换多张图片 | multipart/form-data |
/gpu/status |
GET | v1.1 查询 GPU 加速状态 | - |
/performance |
GET | v1.1 查询内存和性能指标 | - |
/checkpoint |
POST | v1.1 创建批量任务检查点 | application/json |
/checkpoint/{id} |
GET | v1.1 查询检查点状态 | - |
/workspace |
POST | v1.1 保存工作区 | application/json |
/workspace/{name} |
GET | v1.1 加载工作区 | - |
/ocr/detect |
POST | v1.1 检测文字区域 | multipart/form-data |
/ocr/recognize |
POST | v1.1 识别文字内容 | multipart/form-data |
响应 200:
{
"status": "ok",
"version": "2.0.0"
}响应 200:
[
{
"name": "bw",
"colormode": "binary",
"hierarchical": "stacked",
"mode": "spline",
"color_precision": 6,
"layer_difference": 16,
"filter_speckle": 4
},
{
"name": "poster",
"colormode": "color",
"hierarchical": "stacked",
"mode": "spline",
"color_precision": 6,
"layer_difference": 16,
"filter_speckle": 4
}
]同步转换单张图片,直接返回 SVG 文件。
请求参数(Form Data):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
file |
File | 是 | 位图文件(PNG/JPG/WEBP/BMP/TIFF) |
preset |
string | 否 | 预设名称,默认 poster |
options |
string | 否 | JSON 字符串,覆盖预设参数 |
curl 示例:
curl -X POST "http://localhost:8000/convert" \
-F "file=@logo.png" \
-F "preset=logo" \
-F "options={\"color_precision\": 7, \"filter_speckle\": 2}" \
--output logo.svg响应 200: 返回 image/svg+xml 文件。
响应 400:
{
"detail": "Unsupported input format: .gif. Supported: .bmp, .jpg, .jpeg, .png, .tif, .tiff, .webp"
}响应 500:
{
"detail": "Conversion failed: ..."
}启动异步转换任务,立即返回任务 ID。
请求参数(Form Data):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
file |
File | 是 | 位图文件 |
preset |
string | 否 | 预设名称,默认 poster |
options |
string | 否 | JSON 字符串,覆盖预设参数 |
curl 示例:
curl -X POST "http://localhost:8000/convert/async" \
-F "file=@photo.jpg" \
-F "preset=photo" \
-F "options={\"color_precision\": 8}"响应 200:
{
"task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "pending"
}查询异步任务状态。
curl 示例:
curl "http://localhost:8000/status/a1b2c3d4-e5f6-7890-abcd-ef1234567890"响应 200(进行中):
{
"task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "running",
"progress": 0.5,
"result": null,
"error": null,
"created_at": "2026-06-08T12:00:00",
"started_at": "2026-06-08T12:00:01",
"completed_at": null
}响应 200(已完成):
{
"task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "completed",
"progress": 1.0,
"result": {
"svg_path": "/tmp/vs-api-xxx/uploads/xxx/photo.svg",
"duration": 2.34,
"stats": { "paths": 42, "file_size": 15360 }
},
"error": null,
"created_at": "2026-06-08T12:00:00",
"started_at": "2026-06-08T12:00:01",
"completed_at": "2026-06-08T12:00:03"
}响应 404:
{
"detail": "Task not found: a1b2c3d4-..."
}下载已完成任务的结果文件。
路径参数:
| 参数 | 类型 | 说明 |
|---|---|---|
task_id |
string | 异步任务 ID |
format |
string | 格式:svg、pdf、png |
curl 示例:
# 下载 SVG
curl "http://localhost:8000/download/a1b2c3d4-.../svg" --output result.svg
# 下载 PDF
curl "http://localhost:8000/download/a1b2c3d4-.../pdf" --output result.pdf
# 下载 PNG 预览
curl "http://localhost:8000/download/a1b2c3d4-.../png" --output result.png响应 200: 返回对应格式的文件。
响应 400(任务未完成):
{
"detail": "Task is not completed yet. Current status: running"
}响应 404:
{
"detail": "Task not found: a1b2c3d4-..."
}上传图片获取智能预设推荐。
请求参数(Form Data):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
file |
File | 是 | 位图文件 |
curl 示例:
curl -X POST "http://localhost:8000/recommend" \
-F "file=@logo.png"响应 200:
{
"preset": "logo",
"confidence": 0.92,
"reason": "Low color count, high edge density, near-square aspect ratio",
"features": {
"color_count": 4,
"edge_density": 0.35,
"aspect_ratio": 1.02,
"symmetry": 0.88
}
}批量异步转换多张图片。
请求参数(Form Data):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
files |
File[] | 是 | 多个位图文件(字段名均为 files) |
preset |
string | 否 | 预设名称,默认 poster |
options |
string | 否 | JSON 字符串,覆盖预设参数 |
curl 示例:
curl -X POST "http://localhost:8000/batch" \
-F "files=@image1.png" \
-F "files=@image2.jpg" \
-F "files=@image3.png" \
-F "preset=poster"响应 200:
{
"task_ids": [
"task-id-1",
"task-id-2",
"task-id-3"
]
}| HTTP 状态码 | 说明 | 常见场景 |
|---|---|---|
| 200 | 成功 | 正常响应 |
| 400 | 请求参数错误 | 不支持的文件格式、无效的 options JSON、任务未完成时下载 |
| 404 | 资源未找到 | 任务 ID 不存在、输出文件已过期 |
| 500 | 服务器内部错误 | 转换过程异常、PDF/PNG 导出失败 |
Bitmap Vector Studio 内置标准库客户端 VectorStudioClient,零第三方依赖。
from pathlib import Path
from vector_studio.api_client import VectorStudioClient
client = VectorStudioClient("http://localhost:8000")
# 检查服务健康
health = client.health()
print(health) # {'status': 'ok', 'version': '2.0.0'}from pathlib import Path
from vector_studio.api_client import VectorStudioClient
client = VectorStudioClient("http://localhost:8000")
svg_bytes = client.convert(
Path("logo.png"),
preset="logo",
options={"color_precision": 7, "filter_speckle": 2}
)
Path("output.svg").write_bytes(svg_bytes)import time
from pathlib import Path
from vector_studio.api_client import VectorStudioClient
client = VectorStudioClient("http://localhost:8000")
# 提交异步任务
task_id = client.convert_async(Path("photo.jpg"), preset="photo")
print(f"Task ID: {task_id}")
# 轮询状态
while True:
status = client.get_status(task_id)
print(f"Status: {status['status']}, Progress: {status['progress']}")
if status["status"] in ("completed", "failed"):
break
time.sleep(1)
# 下载结果
if status["status"] == "completed":
svg_bytes = client.download(task_id, format="svg")
Path("result.svg").write_bytes(svg_bytes)from pathlib import Path
from vector_studio.api_client import VectorStudioClient
client = VectorStudioClient("http://localhost:8000")
images = [Path("a.png"), Path("b.png"), Path("c.png")]
task_ids = client.batch_convert(images, preset="poster")
print(f"Created {len(task_ids)} tasks")
# 等待所有任务完成
for tid in task_ids:
# ... 轮询并下载
passfrom pathlib import Path
from vector_studio.api_client import VectorStudioClient
client = VectorStudioClient("http://localhost:8000")
result = client.recommend(Path("unknown.png"))
print(f"Recommended preset: {result['preset']} (confidence: {result['confidence']})")
print(f"Reason: {result['reason']}")curl "http://localhost:8000/health"curl "http://localhost:8000/presets" | python -m json.toolcurl -X POST "http://localhost:8000/convert" \
-F "file=@input.png" \
-F "preset=poster" \
--output result.svg# 提交任务
TASK=$(curl -s -X POST "http://localhost:8000/convert/async" \
-F "file=@input.png" \
-F "preset=logo" | python -c "import sys,json; print(json.load(sys.stdin)['task_id'])")
# 查询状态
curl "http://localhost:8000/status/$TASK"
# 下载结果
curl "http://localhost:8000/download/$TASK/svg" --output result.svgcurl -X POST "http://localhost:8000/batch" \
-F "files=@img1.png" \
-F "files=@img2.jpg" \
-F "preset=bw"curl -X POST "http://localhost:8000/recommend" \
-F "file=@logo.png" | python -m json.toolv1.1 桌面应用通过 Tauri Command 桥接 Python 后端,提供与 Web API 等价的功能,并新增性能、工作区、检查点、OCR 多语言相关 Command。所有 Command 均为异步,前端通过 @tauri-apps/api 调用。
| Command | 参数 | 返回值 | 说明 |
|---|---|---|---|
trace_image |
{ filePath, options } |
{ svgPath, stats, duration } |
单图转换 |
batch_convert |
{ filePaths, options } |
{ taskIds } |
批量转换 |
get_presets |
- | Preset[] |
获取所有预设 |
save_preset |
{ name, options, description } |
{ success } |
保存用户预设 |
delete_preset |
{ name } |
{ success } |
删除用户预设 |
get_history |
{ limit? } |
TaskRecord[] |
获取历史任务 |
clear_history |
- | { success } |
清空历史 |
export_history |
{ format, path? } |
{ filePath } |
导出历史报告 |
get_plugins |
- | PluginInfo[] |
获取插件列表 |
enable_plugin |
{ name } |
{ success } |
启用插件 |
disable_plugin |
{ name } |
{ success } |
禁用插件 |
get_market_presets |
{ backend?, query? } |
MarketPreset[] |
获取市场预设 |
install_market_preset |
{ id, backend? } |
{ success } |
安装市场预设 |
publish_preset |
{ name, token, backend? } |
{ presetId } |
发布预设到市场 |
open_file_dialog |
{ multiple?, filters? } |
string[] |
打开文件对话框 |
save_file_dialog |
{ defaultName?, filter? } |
string |
保存文件对话框 |
check_update |
- | { hasUpdate, version, url } |
检查更新 |
install_update |
- | { success } |
安装更新 |
get_app_version |
- | string |
获取应用版本 |
show_notification |
{ title, body } |
{ success } |
显示系统通知 |
get_gpu_status |
- | { available, backend, memory? } |
v1.1 查询 GPU 状态 |
get_performance |
- | { memory, cpu, cache } |
v1.1 查询性能指标 |
save_workspace |
{ name } |
{ success } |
v1.1 保存工作区 |
load_workspace |
{ name } |
{ files, options } |
v1.1 加载工作区 |
list_workspaces |
- | string[] |
v1.1 列出工作区 |
create_checkpoint |
{ taskIds, options } |
{ checkpointId } |
v1.1 创建检查点 |
resume_checkpoint |
{ checkpointId } |
{ restored, taskIds } |
v1.1 恢复检查点 |
list_checkpoints |
- | CheckpointInfo[] |
v1.1 列出检查点 |
ocr_detect |
{ filePath } |
{ regions } |
v1.1 检测文字区域 |
ocr_recognize |
{ filePath, lang? } |
{ text, regions } |
v1.1 识别文字 |
get_ocr_languages |
- | LanguageInfo[] |
v1.1 获取支持的语言列表 |
import { invoke } from '@tauri-apps/api/tauri';
// 单图转换
const result = await invoke('trace_image', {
filePath: '/path/to/image.png',
options: { preset: 'logo', color_precision: 7 }
});
// 获取预设列表
const presets = await invoke('get_presets');
// 打开文件对话框
const files = await invoke('open_file_dialog', {
multiple: true,
filters: [{ name: 'Images', extensions: ['png', 'jpg', 'webp'] }]
});- 临时文件:API 使用临时目录存储上传文件和转换结果。同步转换(
/convert)在响应后自动清理;异步转换(/convert/async)的结果在任务完成后保留,但重启服务后会丢失。生产环境建议挂载持久化卷。 - 并发限制:异步任务使用全局
TaskQueue,默认 4 个工作线程。可通过VECTOR_STUDIO_WORKERS环境变量调整。 - CORS:API 默认允许所有跨域请求(
allow_origins=["*"]),生产环境建议根据实际需求限制。 - 文件大小:FastAPI 默认上传限制为单个文件,若需处理超大图片,建议在客户端先压缩或调整
max_input_side,或启用 v1.1 的--stream流式处理模式。