跳到主要内容

云渲染 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-Typeapplication/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() 的结果):

字体列表(非系统字体必填):

渲染选项:

Format:
Quality:
1
Multiplier:
1× (输出 1080×1080


请求参数详解

{
"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": {
/* 工作区裁剪矩形 */
}
}

顶层字段

字段类型说明
versionstringfabric.js 版本(目前是 6.9.1),云端会按此版本做兼容解析
width / heightnumber画布像素尺寸
thumbstring可选的缩略图 URL(仅用于展示,不影响渲染)
objectsarray画布上的所有元素,按 z-index 升序排列
clipPathobject工作区裁剪矩形(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"
}
]
}
字段类型说明
fontFamilystring字体名,必须与 objects[].fontFamily 完全一致(区分大小写 / 下划线)
urlstring字体文件 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_JSONjson 字段格式错误 / 缺失检查是否正确调了 store.toJSON()
FONT_LOAD_FAILED字体加载失败检查 url 是否可访问、CORS 是否开放
IMAGE_LOAD_FAILED图片资源加载失败检查 objects[].src 是否可访问
PAYLOAD_TOO_LARGE请求体超过 5MB避免把 base64 图片塞进 JSON,改用远程 URL
UNAUTHORIZEDAPI Key 无效或额度耗尽查看 控制台
INTERNAL_ERROR服务端异常重试;持续失败请联系客服

限制与建议

请求体大小

单次请求的 JSON 不能超过 5MB。如果你的设计稿里有 base64 图片,压缩后很容易超出这个限制。强烈建议把图片先上传到 OSS / CDN,JSON 里只存短 URLsetUploadFunc 可以帮你完成这一步)。

图片 / 字体 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)最高
耗时即时1 ~ 10 秒(取决于资源 + 字体)
适合场景预览 / 交互导出批量 / 高清 / 后台任务
成本免费计入企业套餐额度

延伸阅读