云渲染 API(Cloud Render API)
💼 该 API 面向企业套餐用户开放。如果想在生产环境使用,请通过 定价页面 联系我们开通额度。
什么是云渲染 API?
Ydesign SDK 可以在客户端直接生成图片(通过 store.toDataURL() / store.toBlob())。但以下场景在客户端完成非常困难:
- 批量生成:一次出 1000 张变体图(比如营销素材、商品图、动态海报)
- 后台脚本:定时任务、Webhook 回调、消息队列消费
- 高保真导出:印刷级分辨率、超大画布,浏览器端内存不够
- 无头环境:把渲染工作从用户设备上卸载到服务器,降低 C 端负担
你完全可以自己在服务端跑 fabric.js 来做这件事,但你需要自己处理:Node 端 fabric 的 canvas polyfill、自定义字体加载、跨域图片抓取、Ydesign 扩展字段(__strokeOptions)兼容……
Ydesign 云渲染 API 提供的就是这套服务 —— 上传一份你 store.toJSON() 导出的 fabric JSON,云端返回一张渲染好的图片 URL。底层完全基于 fabric.js + Node.js,保证和客户端像素级一致。

接口概览
- 端点:
POST https://api.ydesign.com/api/render/image - Content-Type:
application/json - 认证:请求头携带
Authorization: Bearer YOUR_API_KEY
最小示例
const req = await fetch('https://api.ydesign.com/api/render/image', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer YOUR_API_KEY',
},
body: JSON.stringify({
// 1) 从 store.toJSON() 导出的完整 fabric JSON
json: store.toJSON(),
// 2) 导出选项
format: 'jpeg',
quality: 1,
multiplier: 1,
// 3) 设计稿用到的自定义字体
fonts: [
{
fontFamily: 'AlibabaPuHuiTi_2_115_Black',
url: 'https://your-cdn.com/fonts/AlibabaPuHuiTi_2_115_Black.ttf',
},
],
}),
});
const { url } = await req.json();
document.getElementById('result').src = url;
Demo
设计稿 JSON(store.toJSON() 的结果):
字体列表(非系统字体必填):
渲染选项:
请求参数详解
{
"json": {
/* fabric.js 格式的设计稿数据 */
},
"format": "jpeg",
"quality": 1,
"multiplier": 1,
"fonts": [
{
"fontFamily": "...",
"url": "..."
}
]
}
json · 设计稿数据(必填)
一份 fabric.js v6 格式的 JSON,通常由 store.toJSON() 直接产出。结构大致如下:
{
"version": "6.9.1",
"width": 1920,
"height": 1080,
"thumb": "https://...",
"objects": [
/* 画布上的所有元素 */
],
"clipPath": {
/* 工作区裁剪矩形 */
}
}
顶层字段
| 字段 | 类型 | 说明 |
|---|---|---|
version | string | fabric.js 版本(目前是 6.9.1),云端会按此版本做兼容解析 |
width / height | number | 画布像素尺寸 |
thumb | string | 可选的缩略图 URL(仅用于展示,不影响渲染) |
objects | array | 画布上的所有元素,按 z-index 升序排列 |
clipPath | object | 工作区裁剪矩形(id: 'workarea'),决定最终输出画面 |
objects 数组
每个元素都是原生的 fabric 对象格式。典型的有三类:
矩形(Rect):常用于 workarea 背景板
{
"id": "workarea",
"type": "Rect",
"name": "workarea",
"left": 0,
"top": 0,
"width": 1920,
"height": 1080,
"fill": "#fff",
"selectable": false,
"lockMovementX": true,
"lockMovementY": true
}
图片(Image):
{
"id": "633b5509-...",
"type": "Image",
"src": "https://your-cdn.com/images/background.png",
"left": -3.16,
"top": 0,
"width": 1920,
"height": 1080,
"scaleX": 1,
"scaleY": 1,
"crossOrigin": "anonymous",
"__strokeOptions": {
"color": "rgba(0, 0, 0, 1)",
"width": 6,
"enabled": true,
"alphaThreshold": 10
}
}
💡
__strokeOptions是 Ydesign 扩展的"图片智能描边"配置,云端会自动识别并渲染(对应客户端的ImageStrokeHandler)。不需要额外开关。
文本(Textbox):
{
"id": "911d02d8-...",
"type": "Textbox",
"text": "四个雷区",
"left": 144,
"top": 129,
"width": 350.94,
"fontSize": 86.43,
"fontFamily": "AlibabaPuHuiTi_2_115_Black",
"fontWeight": "normal",
"fill": "rgba(0, 0, 0, 1)",
"textAlign": "center",
"charSpacing": 20,
"lineHeight": 2.16,
"stroke": "red",
"strokeWidth": 25,
"paintFirst": "stroke",
"shadow": {
"blur": 1,
"color": "rgba(0, 0, 0, 1)",
"offsetX": 15.74,
"offsetY": 18.11
}
}
⚠️ 文本如果用了非系统字体,必须在外层
fonts数组里声明对应 URL,否则云端拿不到字体文件、会 fallback 到系统默认字体导致渲染走样。
format · 输出格式
| 值 | 说明 |
|---|---|
jpeg(默认) | 体积最小,不支持透明背景 |
png | 保留透明、无损 |
webp | 体积介于两者之间 |
quality · 图片质量
数值范围 0 - 1,默认 1。仅对 jpeg / webp 生效。
{ "format": "jpeg", "quality": 0.85 }
multiplier · 输出倍数
用于高清导出。multiplier: 2 表示输出图的每一边都放大 2 倍。
| 场景 | 建议值 |
|---|---|
| 网页 / 社交媒体预览 | 1 |
| 高清大图 / Retina 屏 | 2 |
| 印刷级物料(300dpi) | 3 ~ 4 |
📏 画布 1920×1080 +
multiplier: 2→ 输出图为 3840×2160。请评估好带宽与存储成本。
fonts · 自定义字体列表
云端没法"知道"你本地装了什么字体,所有非系统字体都必须通过这个数组显式声明 URL:
{
"fonts": [
{
"fontFamily": "AlibabaPuHuiTi_2_115_Black",
"url": "https://your-cdn.com/fonts/AlibabaPuHuiTi_2_115_Black.ttf"
},
{
"fontFamily": "Noto Sans SC",
"url": "https://your-cdn.com/fonts/NotoSansSC-Regular.woff2"
}
]
}
| 字段 | 类型 | 说明 |
|---|---|---|
fontFamily | string | 字体名,必须与 objects[].fontFamily 完全一致(区分大小写 / 下划线) |
url | string | 字体文件 URL。支持 .ttf / .otf / .woff / .woff2,需要支持 HTTPS + CORS |
渲染前云端会并发下载所有字体文件并注册到 Node fabric 的字体表里,完成后再开始绘制。字体加载有 10 秒超时,超时则 fallback 到系统字体并在响应头返回 X-Ydesign-Font-Missing 警告。
响应格式
成功
{
"success": true,
"url": "https://pub-xxx.r2.dev/renders/2026-04-01/xxxx.jpeg",
"width": 1920,
"height": 1080,
"size": 284591,
"duration": 1243
}
| 字段 | 说明 |
|---|---|
url | 渲染好的图片 URL |
width / height | 实际输出尺寸(= 画布尺寸 × multiplier) |
size | 文件大小(字节) |
duration | 服务端渲染耗时(毫秒) |
🕒 生成的图片文件保留 24 小时,过期后不保证可访问。如果需要长期保留,请在你自己的业务侧下载并转存到自有 OSS。
失败
{
"success": false,
"code": "FONT_LOAD_FAILED",
"message": "Failed to load font: AlibabaPuHuiTi_2_115_Black"
}
常见错误码:
code | 含义 | 排查方向 |
|---|---|---|
INVALID_JSON | json 字段格式错误 / 缺失 | 检查是否正确调了 store.toJSON() |
FONT_LOAD_FAILED | 字体加载失败 | 检查 url 是否可访问、CORS 是否开放 |
IMAGE_LOAD_FAILED | 图片资源加载失败 | 检查 objects[].src 是否可访问 |
PAYLOAD_TOO_LARGE | 请求体超过 5MB | 避免把 base64 图片塞进 JSON,改用远程 URL |
UNAUTHORIZED | API Key 无效或额度耗尽 | 查看 控制台 |
INTERNAL_ERROR | 服务端异常 | 重试;持续失败请联系客服 |
限制与建议
请求体大小
单次请求的 JSON 不能超过 5MB。如果你的设计稿里有 base64 图片,压缩后很容易超出这个限制。强烈建议把图片先上传到 OSS / CDN,JSON 里只存短 URL(setUploadFunc 可以帮你完成这一步)。
图片 / 字体 URL 的 CORS
服务端渲染时需要抓取所有远程资源。请确保:
- 图片 URL 返回
Access-Control-Allow-Origin: * - 字体 URL 返回
Access-Control-Allow-Origin: * - 不要使用需要登录态 / 时效 token 的私有链接
并发与速率限制
企业套餐默认:
- 并发:10 QPS
- 单次渲染时长:最多 30 秒
- 月度额度:按套餐阶梯(基础版 / 高级版 / 定制版)
超出后请求返回 429 Too Many Requests,请做客户端退避重试。
典型场景示例
批量生成带动态文案的营销素材
import fs from 'node:fs/promises';
const template = JSON.parse(await fs.readFile('./template.json', 'utf-8'));
const candidates = ['春节特惠', '618 狂欢', '双 11 大促'];
for (const title of candidates) {
// 用同一份模板,只替换第 4 个元素(主标题)的 text
const cloned = structuredClone(template);
cloned.objects[3].text = title;
const res = await fetch('https://api.ydesign.com/api/render/image', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer YOUR_API_KEY',
},
body: JSON.stringify({
json: cloned,
format: 'jpeg',
quality: 0.9,
multiplier: 2,
fonts: [
{
fontFamily: 'AlibabaPuHuiTi_2_115_Black',
url: 'https://your-cdn.com/fonts/AlibabaPuHuiTi_2_115_Black.ttf',
},
],
}),
});
const { url } = await res.json();
console.log(`${title} →`, url);
}
Node.js 后端直接转存到 S3
import AWS from '@aws-sdk/client-s3';
const res = await fetch('https://api.ydesign.com/api/render/image', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer YOUR_API_KEY',
},
body: JSON.stringify({ json, format: 'png', multiplier: 2, fonts }),
});
const { url } = await res.json();
// 云渲染 API 返回的 URL 只保留 24 小时,立刻下载转存
const imageRes = await fetch(url);
const buffer = Buffer.from(await imageRes.arrayBuffer());
const s3 = new AWS.S3Client({ region: 'us-east-1' });
await s3.send(
new AWS.PutObjectCommand({
Bucket: 'my-design-renders',
Key: `designs/${Date.now()}.png`,
Body: buffer,
ContentType: 'image/png',
})
);
客户端"一键导出高清图"
import { Button, message } from 'antd';
import { observer } from 'mobx-react-lite';
export const ExportHDButton = observer(({ store }) => {
const handleExport = async () => {
const key = 'export';
message.loading({ content: '云端渲染中…', key });
try {
const res = await fetch('https://api.ydesign.com/api/render/image', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${import.meta.env.VITE_YDESIGN_KEY}`,
},
body: JSON.stringify({
json: store.toJSON(),
format: 'png',
multiplier: 4, // 4 倍超清
fonts: store.fonts.map(f => ({
fontFamily: f.fontFamily,
url: f.url,
})),
}),
});
const { url } = await res.json();
window.open(url, '_blank');
message.success({ content: '渲染完成', key });
} catch (e) {
message.error({ content: '渲染失败,请重试', key });
}
};
return (
<Button type="primary" onClick={handleExport}>
导出高清图(4×)
</Button>
);
});
与客户端导出的差异
| 维度 | 客户端 store.toDataURL() | 云端 /api/render/image |
|---|---|---|
| 执行位置 | 用户浏览器 | Ydesign 服务器 |
| 字体 | 依赖用户已加载 | 需显式传 fonts 数组 |
支持的 multiplier | 受浏览器内存限制(通常 ≤ 4) | 最高 8× |
| 耗时 | 即时 | 1 ~ 10 秒(取决于资源 + 字体) |
| 适合场景 | 预览 / 交互导出 | 批量 / 高清 / 后台任务 |
| 成本 | 免费 | 计入企业套餐额度 |
延伸阅读
- 👉 Store API · 导入导出 —— 客户端
toDataURL/toBlob/saveAsImage - 👉 编辑器配置 · 后端对接 ——
setBaseURL/setAPI - 👉 定制化 · 数据加载与导出