1、产品核心功能概览
1.1图片处理功能概览
该编辑器当前支持图片翻译标准版,图片翻译Pro版,智能消除标准版,智能消除Pro版,智能抠图,支持批量上传图片。图片进行翻译/消除/抠图后,可以对局部进行二次编辑,满足用户对高质量多语言营销物料的制作需求。
API名称 | 核心功能 | 批量上传图片 | 二次编辑能力 |
图片翻译标准版 |
|
|
|
图片翻译Pro 版 | |||
智能消除标准版 | 支持多种方式的定向消除
|
| |
智能消除Pro版 |
| ||
智能抠图 |
|
1.2方案选型
本期图像编辑器产品对外提供两种接入形态,二者共用同一套「iframe + postMessage」的通信框架,差异仅在于所嵌入的能力路由与输入参数。您可以根据下表选择匹配自身业务的方案。
如何选择:
需要一站式、多能力串联、且希望翻译数据不流出自身业务系统 → 选方案A。
已经对接了翻译、抠图、消除的API、仅需要对既有处理结果做人工二次编辑 → 选方案B。
维度 | 方案A:一站式图像工作台 | 方案B:二次编辑 |
定位 | 融合了翻译、抠图、消除能力和编辑能力,一个端面中搞定所有,即一站式工作台 | 在调用了相关API后,针对部分图片进行二次编辑,属于「API + 编辑器」两段式 |
典型使用场景 | 终端用户希望翻译/消除/抠图的处理与编辑闭环在一个界面内 | 调用API后,根据实际需要选择目标图片后进入编辑器做局部优化 |
数据管理 | 全部处理和存储在接入方的工作台内 | 翻译/消除/抠图由 API 完成,编辑器仅承接二次编辑 |
可组合能力 | 基础能力:5个处理能力,可单选,可多选 编辑能力:贴纸/素材/文字,可单选,可多选 通用能力:必选包含原图对照,撤销,重做,下载,保存;可选包含返回上级页面 | |
计费方式 | 使用图片翻译标准版,图片翻译Pro版,智能消除标准版,智能消除Pro版,智能抠图,文本翻译能力时收费 | |
1.3多语言版本
端面支持中文(简体),英文,日文,韩文切换,默认中文版本,详见下方3.3.6处
2、产品功能说明
2.1端面的核心模块
核心模块 | Demo | |
左侧控制台 |
|
|
左侧控制台 |
|
|
顶栏常驻 | 通用能力
|
|
右侧编辑区 | 图片翻译 |
|
智能消除标准版 智能消除pro版 智能抠图 | 无 | |
中央画布 |
|
|
2.2编辑态业务规则
2.2.1图片处理逻辑
上传图片
单次可传一张或多张,单次最多25张,
多次总和25张
图片处理,处理按钮(立即翻译/消除/抠图)会对已上传的所有图片生效
如您仅想要对单张图进行处理请上传一张图
如您想对多张图进行处理请上传多张图
2.2.2图片继承逻辑
继承关系,满足图片像素和大小要求即可被继承
图片翻译
格式:JPG、JPEG、PNG、BMP、WEBP
像素宽高均:≤4000
大小:≤10MB
智能消除标准版&智能抠图
格式:JPG、JPEG、PNG、BMP、WEBP
像素:100×100 至 3000×3000
大小:≤10MB
智能消除Pro版
格式:JPG、JPEG、PNG、BMP、WEBP
像素 256×256 至 3000×3000,
大小 ≤ 10MB
继承的触发规则
上传图片成功后,继承已上传成功的图片,不继承对该图片的处理结果
继承的校验规则
以目标能力(翻译/消除/抠图)的图片要求(像素及文件大小)作为校验条件
符合条件则允许继承
不符合条件则提示“暂不符合要求,请您重新上传符合要求的图片”
2.2.3二次编辑的规则
仅支持对单张图进行二次编辑,不支持对多张图二次编辑
图片翻译
当用户点击翻译后,处理成功后则右侧展示完整编辑面板
智能消除&智能抠图
当用户点击抠图/消除后,右侧没有编辑面板
当用户点击抠图/消除后,启动了顶栏的文字/贴纸/素材时,右侧展示对应的编辑项
2.2编辑态产品详情
2.2.1翻译/消除/抠图处理
功能区 | 功能描述 | Demo | |
能力配置面板 | 能力Tab切换 | 能力项
|
|
左侧配置面板 | 主传图框 | 通用能力,适用于5种能力
| 单张图传图框⬇️
多张图传图框⬇️
|
左侧配置面板 | 传图进度 |
|
|
左侧配置面板 | 图片翻译-版本 |
|
|
左侧配置面板 | 图片翻译-标准版 |
|
|
左侧配置面板 | 图片翻译-Pro版 |
|
|
左侧配置面板 | 图片翻译-翻译按钮 |
|
|
左侧配置面板 | 智能消除-版本 |
|
|
左侧配置左侧配置面板面板 | 智能消除-标准版 | 标准版 元素消除,区域消除,文字消除,三者为互斥关系
可以指定文本进行消除,支持输入多个文本,每个文本之间用英文逗号隔开。 进行此操作时其他消除方式(例如去除商品主体元素等)不生效
|
|
智能消除-Pro版 |
|
| |
智能消除-消除按钮 |
|
| |
左侧配置面板 | 智能抠图 |
|
点击背景颜色后即可选择更多目标颜色
|
开始抠图
|
| ||
执行态 | 任务列表 | 通用能力,适用于5种能力
UI样式
| 完整端面⬇️
失败态⬇️
|
执行态 | 完整端面 | 图片翻译标准版 |
|
执行态 | 完整端面 | 图片翻译Pro版 |
|
执行态 | 完整端面 | 智能消除标准版 |
|
执行态 | 完整端面 | 智能消除Pro版 |
|
执行态 | 完整端面 | 智能抠图 |
|
结果态 | 保存 | 通用能力,适用于翻译/抠图/消除三种能力 |
|
下载 | 通用能力,适用于翻译/抠图/消除三种能力 | ||
未保存/下载时跳出则弹窗 | 通用能力,适用于翻译/抠图/消除三种能力,当用户未保存/下载时想要返回上级页面,此时会弹窗提醒 |
| |
历史任务 | 任务 | 点击历史按钮,可以查看已处理成功的历史任务
| 顶栏点击“历史”⬇️
进入历史后可以筛选⬇️
|
2.2.1二次编辑能力
二次编辑能力类型 | 功能描述 | Demo |
通用编辑能力 | 适用于翻译(标准版及Pro版)/消除(标准版及Pro版)/抠图
| 添加文字-自定义输入文字⬇️
添加贴纸-平台提供贴纸库⬇️
添加素材-从本地上传素材⬇️
|
特有编辑能力 | 适用于翻译(标准版及Pro版)
|
|
3、接入方式
3.1、整体流程
客户前端向客户服务端发起请求,例如 POST /api/aidge-editor/access-url。
客户服务端根据当前用户身份,向阿里云登录服务申请一次性 Key,并拼接完整的 iframe URL。
客户服务端将完整的 iframe URL 返回给客户前端。
客户前端创建或刷新 iframe,并将 src 设置为该 URL。
阿里云登录服务对 Key 进行校验。校验通过后,进入编辑器页面。
编辑器页面加载完成后,通过 postMessage 向父页面发送加载完成事件。
客户前端收到加载完成事件后,通过 postMessage 向 iframe 发送初始化事件,并携带相应的初始化参数。
建议由客户服务端直接返回完整的 iframe URL,以减少前端拼接错误并降低 Key 泄露风险。客户服务端也可仅返回 Key,由客户前端获取 Key 后立即拼接 iframe URL。
如需对下游用户进行数据隔离,可将用户唯一 ID 传入 RoleSessionName 字段。详见下方 3.2.6 中的 Java 示例代码。
3.2、客户服务端接入
具体实现可参考 免登访问 方案。
3.2.1、创建 RAM 子用户并授权
如子账号已存在,可跳过此步骤。
3.2.2、为 RAM 用户授权 AliyunSTSAssumeRoleAccess

3.2.3、创建 RAM 角色
使用 RAM 主账号登录控制台并创建 RAM 角色,也可通过 RAM API CreateRole 创建。



3.2.4、为角色授权
搜索“Aidge”,并选择对应的权限策略。

3.2.5、获取 roleArn、accessKeyId、accessKeySecret 参数



3.2.6、Java 示例代码
<dependencies>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-sts</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.5</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
</dependencies>import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.net.URISyntaxException;
/**
* Aidge 虚商控制台免登接入示例。
* <p>
* 流程:AssumeRole 获取临时凭证 → GetSigninToken → 构造 federation 免登链接。
*/
public class Test {
private static final String SIGN_IN_DOMAIN = "https://signin.aliyun.com/federation";
/**
* 使用安全令牌获取登录令牌
* https://help.aliyun.com/document_detail/91913.html
*
* @param accesskeyId
* @param accessKeySecret
* @param securityToken
* @return
* @throws IOException
* @throws URISyntaxException
*/
private static String getSignInToken(String accesskeyId, String accessKeySecret, String securityToken)
throws IOException, URISyntaxException {
URIBuilder builder = new URIBuilder(SIGN_IN_DOMAIN);
builder.setParameter("Action", "GetSigninToken")
.setParameter("AccessKeyId", accesskeyId)
.setParameter("AccessKeySecret", accessKeySecret)
.setParameter("SecurityToken", securityToken)
.setParameter("TicketType", "mini");
HttpGet request = new HttpGet(builder.build());
CloseableHttpClient httpclient = HttpClients.createDefault();
try (CloseableHttpResponse response = httpclient.execute(request)) {
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String context = EntityUtils.toString(response.getEntity());
JSONObject jsonObject = JSON.parseObject(context);
return jsonObject.getString("SigninToken");
} else {
System.out.println(response.getStatusLine());
}
}
return null;
}
private static String getChatbotLoginUrl(String pageUrl, String signInToken) throws URISyntaxException {
URIBuilder builder = new URIBuilder(SIGN_IN_DOMAIN);
builder.setParameter("Action", "Login");
// 登录失效后的跳转地址,一般配置为自建 Web 服务中用于 302 跳转的 URL
builder.setParameter("LoginUrl", "https://signin.aliyun.com/login.htm");
// 实际访问的 Aidge 控制台页面,例如首页或编辑器页面
builder.setParameter("Destination", pageUrl);
builder.setParameter("SigninToken", signInToken);
HttpGet request = new HttpGet(builder.build());
return request.getURI().toString();
}
/**
* 通过 AssumeRole 接口获取用户临时身份
* 参考 https://help.aliyun.com/document_detail/28763.html
*
* @param roleArn RAM 角色 ARN,格式:acs:ram::<主账号UID>:role/<角色名>
* @param accessKeyId 调用方 AK
* @param accessKeySecret 调用方 SK
* @param roleSessionName 用户自定义会话名,可用于用户级别的访问审计。格式:^[a-zA-Z0-9\.@\-_]+$
* @return
* @throws ClientException
*/
private static AssumeRoleResponse.Credentials assumeRole(String roleArn, String accessKeyId,
String accessKeySecret, String roleSessionName)
throws ClientException {
String defaultRegion = "cn-hangzhou";
IClientProfile profile = DefaultProfile.getProfile(defaultRegion, accessKeyId, accessKeySecret);
DefaultAcsClient client = new DefaultAcsClient(profile);
AssumeRoleRequest request = new AssumeRoleRequest();
// 直接使用拼接好的角色 ARN
request.setRoleArn(roleArn);
// 用户自定义参数。此参数用来区分不同的令牌,可用于用户级别的访问审计。格式:^[a-zA-Z0-9\.@\-_]+$
request.setRoleSessionName(roleSessionName);
// 指定过期时间,单位为秒。可设置为 900~3600,默认值为 3600
request.setDurationSeconds(3600L);
AssumeRoleResponse response = client.getAcsResponse(request);
return response.getCredentials();
}
public static void main(String[] args) throws IOException, URISyntaxException {
try {
/*
* Step 0:准备子账号并完成权限授权
*/
// 要扮演的 RAM 角色 ARN(由主账号 UID 和角色名拼接),请替换为真实值 acs:ram::${accountId}:role/${roleName}
String roleArn = "按需替换";
// 子账号的 AK 和 SK,需具备 AliyunSTSAssumeRoleAccess 权限,请替换为真实值
String accessKeyId = "按需替换";
String accessKeySecret = "按需替换";
// 业务侧用户 ID:用于同一 RAM 角色下区分真实业务用户,便于访问审计。
// 建议填写业务系统中的用户唯一标识(如 userId),格式需满足:^[a-zA-Z0-9.@-_]+$,长度为 2~64 个字符
String userId = "按需替换";
/*
* Step 1:通过 AssumeRole 接口获取临时 AK、SK 和 SecurityToken
*/
AssumeRoleResponse.Credentials credentials =
assumeRole(roleArn, accessKeyId, accessKeySecret, userId);
System.out.println("Expiration: " + credentials.getExpiration());
System.out.println("Access Key Id: " + credentials.getAccessKeyId());
System.out.println("Access Key Secret: " + credentials.getAccessKeySecret());
System.out.println("Security Token: " + credentials.getSecurityToken());
System.out.println("RoleSessionName: " + userId);
/*
* Step 2:获取 SigninToken
*/
String signInToken = getSignInToken(credentials.getAccessKeyId(),
credentials.getAccessKeySecret(),
credentials.getSecurityToken());
System.out.println("Your SigninToken is: " + signInToken);
// 集成 Aidge 编辑器页
String pageUrl = "https://ecoa4service.console.aliyun.com/editor";
String accessUrl = getChatbotLoginUrl(pageUrl, signInToken);
System.out.println("Your PageUrl is : " + accessUrl);
} catch (ClientException e) {
System.out.println("Failed:");
System.out.println("Error code: " + e.getErrCode());
System.out.println("Error message: " + e.getErrMsg());
System.out.println("RequestId: " + e.getRequestId());
}
}
}3.2.7、生成 Key 的服务端要求
Key 生成逻辑必须部署在服务端。服务端应妥善保管 AK、SK、RoleArn 和 Secret 等敏感信息。
每次打开编辑器页面时,都应生成新的 Key。
不得将 Key 作为长期凭证持久化存储。如需记录,应仅保留必要的审计信息,并避免将其明文输出至前端日志、Nginx 访问日志或监控系统。
Key 生成后应立即使用。一次性 Key 的有效期为 30 秒,且仅可使用一次。
刷新或重新打开页面,以及复制链接后再次访问时,都应重新执行服务端 Key 生成流程。
3.3、客户前端接入
在页面中通过 <iframe> 标签引入编辑器,并将 src 设置为服务端返回的地址。详见上方 3.2。
客户前端与编辑器通过 postMessage 进行通信。编辑器的 Origin 为 https://ecoa4service.console.aliyun.com。建议客户前端发送消息时指定该 Origin,接收消息时校验该 Origin。详见下方 3.3.7。
当客户前端收到编辑器 iframe 发送的 pageReady 消息后,可向编辑器发送 action 为 init 的消息,完成初始化。
window.addEventListener("message", (ev: MessageEvent) => {
const { action } = ev.data ?? {};
if (action === "pageReady") {
iframeEle.contentWindow?.postMessage(
{
action: "init",
data: {
tool: "translate",
},
},
editorOrigin,
);
}
});3.3.1、编辑器初始化配置项
序号 | 名称 | 配置字段 | 字段类型 | 是否必填 | 默认值 | 说明 |
1 | 编辑器能力 |
|
| 是 | - | 决定开通哪些能力。可传单个字符串(只开一个能力)或字符串数组(开多个能力,编辑器顶部出现切换 Tab)。
数组中每个能力组各取一个带档位的值,如 |
2 | 图片 URL |
|
| 否 | - | 待翻译图片的 URL。批量模式(uploadMode=multi)下可传数组预置多张。请勿直接使用限制图片访问的电商平台图片链接,建议转存后再传入。如不传入,可在编辑器中手动上传 |
3 | 上传模式 |
|
| 否 |
|
|
4 | 批量上限 |
|
| 否 |
| 仅 |
5 | 原始语向 |
|
| 否 | - | 如不传入,可在编辑器中手动选择。支持的语向详见下方 7.1 |
6 | 目标语向 |
|
| 否 | - | 如不传入,可在编辑器中手动选择。支持的语向详见下方 7.1 |
7 | 界面语言 |
|
| 否 |
| 编辑器界面语种。可选 |
8 | 原文保留(品牌/商品名)默认值 |
|
| 否 |
|
|
9 | 二次编辑 |
|
| 否 |
|
|
10 | 二次编辑数据 |
|
| 否 |
| 翻译后的结果数据,包含图层信息,可从 API 返回结果中获取 |
11 | 生产拦截 |
|
| 否 |
|
|
12 | 生产拦截(文本翻译) |
|
| 否 |
| 针对右侧面板的文本翻译的生产拦截,与 |
13 | 是否执行调用 |
|
| 否 |
|
|
14 | 编辑器 UI 配置 |
|
| 否 |
| 对于每个子配置项,如果用户已传入自定义值,则以自定义值为准;未传入的子配置项将使用下表中的默认值 |
3.3.2、editorConfig 配置项
以下配置项均为选填。按能力分组,未开通的能力对应的配置项不生效。空串 '' 是有意义的值:各 Tip 字段设为 '' 表示不展示对应 tooltip;单档入口下档位标签设为 '' 表示不展示标签。
通用配置
序号 | 名称 | 配置字段 | 类型 | 默认值 | 说明 |
1 | 返回按钮是否展示 |
|
|
|
|
2 | 大标题文案 |
|
|
| 左侧边栏大标题 |
3 | 「历史」按钮是否展示 |
|
|
|
|
4 | 「历史」按钮文案 |
|
|
| - |
5 | 「历史任务」标题文案 |
|
|
| - |
6 | 「点击上传图片」按钮文案 |
|
|
| - |
7 | 「文字」按钮显隐 |
|
|
|
|
8 | 「贴纸」按钮显隐 |
|
|
|
|
9 | 「素材」按钮显隐 |
|
|
|
|
图片翻译(标准版&Pro版)
序号 | 名称 | 配置字段 | 类型 | 默认值 | 说明 |
10 | 「图片翻译」标题文案 |
|
|
| - |
11 | 「标准版」标签文案 |
|
|
|
|
12 | 「Pro 版」标签文案 |
|
|
|
|
13 | 「标准版」说明文案 |
|
|
| 设为 |
14 | 「Pro 版」说明文案 |
|
|
| 设为 |
15 | 「语言」小标题文案 |
|
|
| - |
16 | 「原始语向」标签文案 |
|
|
| - |
17 | 「原始语向」说明文案 |
|
|
| 设为 |
18 | 「目标语向」标签文案 |
|
|
| - |
19 | 「目标语向」说明文案 |
|
|
| 设为 |
20 | 「品牌名保护)」标签文案 |
|
|
| - |
21 | 「品牌名保护)」说明文案 |
|
|
| 设为 |
22 | 品牌名保护默认值 | includingProductAreaDefaultValue | boolean | true | true默认选中; false默认不选中 |
23 | 翻译按钮文案 |
|
|
| - |
24 | 「是否翻译文字」开关文案 |
|
|
| 仅文案可配,开关规则不变。 |
智能消除-标准版
序号 | 名称 | 配置字段 | 类型 | 默认值 | 说明 |
25 | 消除标题文案 |
|
|
| - |
26 | 「标准版」标签文案 |
|
|
| 设为 |
27 | 「Pro 版」标签文案 |
|
|
| 设为 |
28 | 「标准版」说明文案 |
|
|
| 设为 |
29 | 「Pro 版」说明文案 |
|
|
| 设为 |
30 | 「商品主体元素」消除入口显隐 |
|
|
| 控制「去除商品主体元素」入口的显隐。仅在智能消除标准版时有此功能
|
31 | 「非商品主体元素」消除入口显隐 |
|
|
| 控制「去除非商品主体元素」入口的显隐。仅在智能消除标准版时有此功能
|
32 | 「区域消除」入口显隐 |
|
|
| 控制「框选/圈选区域消除」入口的显隐。仅在智能消除标准版时有此功能
|
33 | 「文本消除」入口显隐 |
|
|
| 控制「指定文本消除」入口的显隐。仅在智能消除标准版时有此功能
|
34 | 消除按钮文案 |
|
|
| - |
智能抠图
序号 | 名称 | 配置字段 | 类型 | 默认值 | 说明 |
35 | 抠图标题文案 |
|
|
| - |
36 | 「背景类型」标签文案 |
|
|
| - |
37 | 「纯色底」选项文案 |
|
|
| - |
38 | 「透明底」选项文案 |
|
|
| - |
39 | 背景默认值 |
|
|
| 枚举值: |
40 | 「输出尺寸」分组标题文案 |
|
|
| - |
41 | 「目标宽度」标签文案 |
|
|
| - |
42 | 「目标高度」标签文案 |
|
|
| - |
43 | 抠图按钮文案 |
|
|
| - |
3.3.3、编辑器消息体
编辑器通过 postMessage 发送的消息体结构如下:
{
biz: "translate",
action: "generate",
data: {
imageNum: 1,
},
}字段说明:
字段 | 示例值 | 是否必返 | 含义 |
|
| 否 | 业务标识。图片翻译标准版为 |
|
| 是 | 消息类型 |
|
| 否 | 消息数据 |
3.3.4、编辑器报错消息体
编辑器通过 postMessage 发送的报错消息体结构如下:
{
biz: "translate",
action: "error",
errCode: "translate-taskError",
errMessage: errMsg,
}字段说明:
字段 | 示例值 | 是否必返 | 含义 |
|
| 是 | 发生错误的业务标识 |
|
| 是 | 消息类型。报错消息固定为 |
|
| 是 |
|
|
| 是 | 错误信息 |
接入方可根据 errCode 自定义面向用户的错误提示。
3.3.5、编辑器发送的消息
通信方向:编辑器 iframe → 客户前端
| 触发时机 | 消息体 | 关键数据 | 关联消息 |
| 编辑器页面加载完成 |
| 无其他字段 | 客户前端收到后发送 |
| 用户点击返回按钮,且初始化配置中 |
| 无其他字段 | - |
| 用户准备发起付费 API 调用,且初始化配置中 |
|
| 客户前端需返回 |
| 编辑器业务执行失败 |
|
详见上方 3.3.4 | - |
| 生成任务执行成功 |
|
详见下方 5.1 | - |
| 用户点击“保存”或“下载”,或编辑器响应 |
|
详见下方 5.3 | 可由 |
3.3.6、编辑器可接收的消息
通信方向:客户前端 → 编辑器 iframe
| 发送时机 | 消息体 | 关键数据 | 编辑器处理结果 |
| 客户前端收到 |
|
详见上方 3.3.1 | 根据配置完成编辑器初始化 |
| 需运行时切换界面语种时 |
|
| 动态切换界面语言(无需重新加载) |
| 客户前端收到 |
|
详见下方 4.1 | 根据 |
| 客户前端自行完成 API 调用后 |
|
详见下方 4.3 | 加载并展示结果 |
| 客户前端需主动获取当前完整结果时 |
| 无其他字段 详见下方 5.1 | 编辑器通过 |
3.3.7、示例前端代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Aidge 编辑器接入示例</title>
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0;
}
#editorIframe {
display: block;
width: 100%;
height: 100%;
border: 0;
}
</style>
</head>
<body>
<iframe
id="editorIframe"
title="Aidge 在线编辑器"
allow="clipboard-read; clipboard-write"
></iframe>
<script>
const editorIframe = document.getElementById("editorIframe");
// 编辑器页面的 Origin,用于校验和发送 postMessage。
const editorOrigin = "https://ecoa4service.console.aliyun.com";
// 编辑器初始化参数。请根据实际业务替换示例值。
const editorInitData = {
// translate:图片翻译标准版
// translatePro:图片翻译 Pro 版
// translateBoth:标准版 + Pro 版,可在编辑器中切换
tool: "translateBoth",
// 以下三项为选填项。不传 imageUrl 时,可在编辑器中手动上传图片。
imageUrl: "https://example.com/source.jpg",
sourceLanguage: "zh",
targetLanguage: "en",
// 开启生产拦截。编辑器发送 generate 后,会等待父页面返回 respond。
charge: true,
// editorConfig 及其所有子配置项均为选填项。
editorConfig: {
editorTitle: "图片编辑器",
showHistory: true,
historyButtonText: "历史",
imageTransPanelTitle: "图片翻译",
historyPanelTitle: "历史任务",
imageUploaderButtonText: "点击上传图片",
imageTransLabel: "标准版",
imageTransProLabel: "Pro 版",
imageTransTip: "高性价比",
imageTransProTip: "翻译更精准",
imageTransOptionsTitle: "语言",
sourceLanguageLabel: "原始语向",
sourceLanguageTip: "被翻译内容的语向",
targetLanguageLabel: "目标语向",
targetLanguageTip: "想要翻译成的语向",
includingProductAreaLabel: "原文保留(品牌名)",
includingProductAreaTip: "开启后主流品牌将不会被翻译",
includingProductAreaDefaultValue: true,
imageTransButtonText: "开始翻译",
showAddText: true,
showAddSticker: true,
showAddImage: true
}
};
/**
* 判断是否允许本次付费 API 调用。
* 实际接入时,请在此处调用客户服务端,校验用户余额或权限。
*/
async function checkGenerationPermission({ biz, imageNum, data }) {
console.log("待确认的生产请求:", {
biz,
imageNum,
data
});
// TODO:根据实际业务返回校验结果。
return true;
}
/**
* 处理生产拦截请求。
*/
async function handleGenerate(message) {
const { biz, data } = message;
const { imageNum } = data ?? {};
let success = false;
try {
success = await checkGenerationPermission({
biz,
imageNum,
data
});
} catch (error) {
console.error("生产请求校验失败:", error);
}
// biz 必须与编辑器发送的 generate 消息保持一致。
editorIframe.contentWindow.postMessage(
{
biz,
action: "respond",
success
},
editorOrigin
);
}
/**
* 处理编辑器报错。
*/
function handleEditorError(message) {
const { biz, errCode, errMessage } = message;
console.error("编辑器报错:", {
biz,
errCode,
errMessage
});
// TODO:可根据 errCode 自定义面向用户的错误提示。
}
/**
* 处理算法生成结果。
* 该结果不包含用户在编辑器中的后续编辑操作。
*/
function handleTaskSuccess(message) {
const { biz, data } = message;
const results = Array.isArray(data) ? data : [];
console.log("生成任务完成:", {
biz,
results
});
// TODO:根据实际业务处理算法生成结果。
}
/**
* 处理用户点击“保存”或“下载”后返回的最终结果。
*/
function handleSubmitAll(message) {
const results = Array.isArray(message.data) ? message.data : [];
console.log("收到编辑器最终结果:", results);
// TODO:将 schema 原样保存,不得修改其内容。
// TODO:及时转存结果图片,返回的图片 URL 默认有效期为 7 天。
}
/**
* 监听编辑器 iframe 发送的消息。
*/
window.addEventListener("message", function (event) {
// 只接收当前编辑器 iframe 发送的消息。
if (event.source !== editorIframe.contentWindow) {
return;
}
// 校验消息来源,避免处理其他网站发送的消息。
if (event.origin !== editorOrigin) {
console.warn("忽略未知来源的消息:", event.origin);
return;
}
const message = event.data;
if (!message || typeof message !== "object") {
return;
}
switch (message.action) {
case "pageReady":
console.log("编辑器页面已准备就绪");
// 收到 pageReady 后发送初始化参数。
editorIframe.contentWindow.postMessage(
{
action: "init",
data: editorInitData
},
editorOrigin
);
break;
case "generate":
// 生产拦截为异步流程,处理结果将通过 respond 返回编辑器。
void handleGenerate(message);
break;
case "error":
handleEditorError(message);
break;
case "taskSuccess":
handleTaskSuccess(message);
break;
case "submitAll":
handleSubmitAll(message);
break;
default:
console.warn("收到未识别的编辑器消息:", message);
}
});
/**
* 从客户服务端获取编辑器地址,并设置 iframe src。
*/
async function loadEditor() {
try {
const response = await fetch("/api/aidge-editor/access-url", {
method: "POST",
cache: "no-store"
});
if (!response.ok) {
throw new Error(`获取编辑器地址失败:HTTP ${response.status}`);
}
const result = await response.json();
if (!result.src) {
throw new Error("服务端未返回编辑器 src");
}
const editorUrl = new URL(result.src);
if (editorUrl.protocol !== "https:") {
throw new Error("编辑器地址必须使用 HTTPS");
}
// 消息监听器注册完成后再加载 iframe,避免错过 pageReady。
// 一次性 Key 生成后应立即使用。
editorIframe.src = editorUrl.href;
} catch (error) {
console.error("编辑器加载失败:", error);
}
}
loadEditor();
</script>
</body>
</html>3.3.8、biz 业务标识对照表
biz 用于标识消息属于哪种能力/档位。接入方收到编辑器消息后按 biz 路由;回传 respond / applyToolResult 时须原样带回相同的 biz。
能力 / 档位 | tool 入口取值 | 消息 | 提交 ApiType |
图片翻译标准版 |
|
|
|
图片翻译 Pro 版 |
|
|
|
图片翻译双档 |
| 按当前档位取 | 同上 |
智能消除标准版 |
|
|
|
智能消除 Pro 版 |
|
|
|
智能消除双档 |
| 按当前档位取 | 同上 |
智能抠图 |
|
|
|
文本翻译(右侧面板) | —(随任意能力) |
| —(仅 |
口径要点:图片翻译的biz是档位名(translate/translatePro),不是 ApiType;上表biz适用于该能力对宿主发出的全部报文(generate/respond/applyToolResult/taskSuccess/submitAll/error)。
4、定制化功能
4.1、生产拦截
仅当编辑器初始化配置中的 charge 设置为 true 时,生产拦截功能才会生效。
生产拦截功能允许接入方控制用户的付费 API 调用请求。编辑器将根据接入方返回的结果,决定是否继续执行调用,从而实现调用前的二次确认。
使用场景:用户每次在编辑器中调用付费 API 时,接入方可验证用户的可用余额或权限是否满足要求
实现步骤:
监听编辑器页面发送的消息,并实现接入方的业务判断逻辑。
let receiveBiz = "";
window.addEventListener("message", (ev: MessageEvent) => {
const { data, action, biz } = ev.data ?? {};
if (action === "generate") {
// 保存业务类型,回复编辑器时需要原样传回
receiveBiz = biz;
// 本次用户准备生成的图片数量
const { imageNum } = data ?? {};
console.log("生产请求:", {
biz,
imageNum,
data,
});
// TODO:在这里判断用户余额、权限等
}
});返回消息,控制是否继续生产流程。当返回消息中的
success为true时,继续执行调用;为false时,中断调用并向用户显示提示。
// true:继续生产并产生费用
// false:中断生产流程
const success = true;
iframeEle.contentWindow?.postMessage(
{
biz: receiveBiz,
action: "respond",
success,
},
editorOrigin,
);
biz随能力不同(图翻档位名 / 消除·抠图 ApiType / 文本翻译textTranslation,见 §3.3.8),务必原样回传。
4.2、二次编辑
仅当编辑器初始化配置中的 reEdit 设置为 true 时,二次编辑功能才会生效。
二次编辑功能支持在编辑器中加载历史结果数据并继续编辑。启用该功能时,接入方需通过初始化配置中的 reEditData 传入历史结果数据。该数据可使用 API 返回结果中的 genFiles 字段(详见下方第 6 节),也可使用编辑器返回的结果数据(详见下方 5.2 和 5.3)。
reEditData为string,反序列化后为EditorData[](结构见 §5.3)。数据可取自 API 返回的genFiles(§6)或编辑器返回的结果数据(§5.2 / §5.3)。已支持多张图:数组中每个元素对应一张图,编辑器会重建为多任务;单张时传长度为 1 的数组。
tool需与结果对应的能力一致(如抠图结果传tool: "matting"),否则界面能力与数据不匹配。结果数据在存储/传输过程中不得修改,否则可能无法正确加载。
图片翻译二次编辑示例(fileUrl / srcImage / repairedUrl 等为占位,请替换为真实结果 URL):
iframeEle.contentWindow?.postMessage(
{
action: "init",
data: {
tool: "translate",
reEdit: true,
reEditData: JSON.stringify([
{
editInfo: {
goodsRects: { top: 0, left: 0, width: 802, height: 802, degree: 0 },
languages: ["en"],
textAreas: [
{
verticalLayout: "top",
horizontalLayout: "center",
color: "#f6eec1",
fontsize: 50,
lineCount: 1,
content: "凯蒂猫伴睡小夜灯",
texts: [
{
valid: true,
verticalLayout: "top",
horizontalLayout: "center",
color: "#f6eec1",
imageRect: { top: 27, left: 68, width: 692, height: 100, degree: 0 },
textRect: { top: 27, left: 68, width: 692, height: 100, degree: 0 },
fontsize: 50,
language: "en",
value: "Hello Kitty Sleep Companion Night Light",
lineCount: 1
}
]
}
],
resultImageIds: ["xxx"],
repairedUrl: "xxx",
font: ["AlibabaSans-Regular"]
},
srcImage: "xxx",
resultList: [{ language: "en", fileUrl: "xxx" }]
}
])
}
},
editorOrigin
);
智能抠图 / 智能消除二次编辑示例(无文字,textAreas 为空;repairedUrl 为效果图/去背景图,srcImage 为原图):
iframeEle.contentWindow?.postMessage(
{
action: "init",
data: {
tool: "matting", // 消除则传 erase / erasePro / eraseBoth
reEdit: true,
reEditData: JSON.stringify([
{
editInfo: {
languages: [],
textAreas: [],
resultImageIds: [],
repairedUrl: "xxx", // 抠图/消除后的结果图
font: [ ]
},
srcImage: "xxx", // 原图
resultList: [{ language: "", fileUrl: "xxx" }]
}
])
}
},
editorOrigin
);
4.3、接入方自行调用 API
仅当 enableToolExecution=false 时生效。用户触发能力后,编辑器不直接调 API,而是发一个 generate 把整批调用信息交给宿主;宿主一次性完成整批调用后,通过一个 applyToolResult 回传整批结果,由编辑器渲染成任务列表。图片翻译、智能消除、智能抠图三档统一此流程,单张视为长度 1 的整批。
window.addEventListener("message", async (event) => {
const { action, biz, data } = event.data ?? {};
if (action === "generate") {
try {
// data = { imageNum, apiType, items: [{ name, params, detail }] }
// 按 biz 路由到对应能力,遍历 items 整批调用(invokeToolApi 为示例)。
const results = await Promise.all(
data.items.map((item) => invokeToolApi({ biz, params: item.params })),
);
// 回传数组,长度 = data.imageNum,顺序与 items 对应;每份结构与 reEditData
// 的单个元素一致(图片翻译可直接用后端 genFiles;消除/抠图见下方结构)。
const resultData = results.map((r) => r.genFilesItem);
iframeEle.contentWindow.postMessage(
{ biz, action: "applyToolResult", data: resultData }, editorOrigin);
} catch (error) {
console.error("能力 API 调用失败:", error);
// 整批调用失败:data 传空字符串,并由接入方自行 Toast 提示。
iframeEle.contentWindow.postMessage(
{ biz, action: "applyToolResult", data: "" }, editorOrigin);
}
}
});
消除/抠图每份 GenFilesItem 的最小结构(无文字,textAreas 为空数组):
{
editInfo: {
repairedUrl: "https://.../result.png", // 消除/抠图结果图
textAreas: [],
resultImageIds: [],
languages: [],
font: [],
},
srcImage: "https://.../origin.png", // 原图
resultList: [{ language: "", fileUrl: "https://.../result.png" }],
}
biz须与generate.biz一致(见 §3.3.8);data为数组GenFilesItem[],长度 =generate.data.imageNum,按items顺序对应;每份结构与reEditData的单个元素一致。整批调用失败传""。返回份数少于提交张数时,缺失的图按失败处理;非数组/无法解析时整批按失败处理。
智能抠图:结果尺寸可能与原图不同,建议结果图 URL 携带
tps-{宽}-{高}命名(或允许编辑器域跨域读取图片像素),否则画布可能回退到默认尺寸导致渲染错位。
5、结果获取
5.1、生成任务结果获取
用户发起生成请求且调用成功后,接入方可通过监听 action 为 taskSuccess 的消息,获取当次任务的结果数据。
注意:此处的任务结果是算法生成的结果,不是用户修改后的最终结果,因此不包含用户在编辑器中的编辑操作。
interface ResultItem {
id: string;
url: string;
}
type Result = ResultItem[];
window.addEventListener("message", (ev: MessageEvent) => {
const { data, action, biz } = ev.data ?? {};
if (action === "taskSuccess") {
const result: Result = data;
console.log("业务:", biz, "生产任务完成,结果:", result);
}
});5.2、最终结果获取
方式1:事件监听
用户执行以下操作时,编辑器会向接入方返回结果数据:
点击“保存”按钮:返回当前画布的结果图片和协议。
点击“下载”按钮:将结果图片下载到本地,同时返回结果图片和协议。
window.addEventListener("message", (ev: MessageEvent) => {
const { data, action } = ev.data ?? {};
if (action === "submitAll") {
// TODO:在这里处理最终任务结果
console.log("收到任务结果:", data);
}
});方式2:主动获取
接入方可发送 action 为 requestResult 的消息,主动获取编辑器中的结果数据。
iframe.contentWindow?.postMessage(
{
action: "requestResult",
},
editorOrigin,
);编辑器收到上述消息后,会按以下方式返回完整的结果数据。
window.addEventListener("message", (ev: MessageEvent) => {
const { data, action } = ev.data ?? {};
if (action === "submitAll") {
// TODO:在这里处理最终任务结果
console.log("收到任务结果:", data);
}
});5.3、返回的数据格式
返回数据包含用户当前画布的结果图片 url 和结果数据 editData。
结果数据需由接入方自行保存。开启二次编辑功能时,将该数据传入编辑器,即可加载并继续编辑。
注意:结果数据在存储和传输过程中不得进行任何修改,否则可能导致编辑器无法正确读取或加载历史数据。结果图片 URL 的默认有效期为 7 天,请接入方及时转存,以免因链接过期而无法访问。
interface ResultType {
/**
* 本次是否由用户点击「下载图片」触发。
* 下载与保存的报文体完全相同,接入方靠它判断该不该重复计数 / 提示。
*/
isDownload: boolean;
/** 结果 ID,用于跟踪算法结果以及用户调整后的结果 */
id: string;
/** 原图地址(单张,可直接访问的签名 URL) */
originalUrl: string;
/** 结果图地址(单张,可直接访问的签名 URL) */
url: string;
/**
* 编辑器完整数据,类型为 JSON string
* 与初始化参数 reEditData 一致,反序列化后为符合 EditorData 结构的对象数组。
*/
editData: string;
}
interface EditorData {
/** 编辑器完整数据:文字区、用户新增图层、修复底图、字体等 */
editInfo: EditInfo;
/** 原图地址 */
srcImage: string;
/** 结果图列表。按语种分项(算法结构),当前单语种翻译故恒为单元素 */
resultList: ResultImageItem[];
}
interface EditInfo {
/** 商品区域 */
goodsRects?: Rect;
/** 目标语种列表 */
languages: string[];
/** 文字区列表(算法识别出的「原文 → 译文」区域) */
textAreas: TextArea[];
/** 结果图 ID 列表 */
resultImageIds: string[];
/** 去字后的修复底图地址 */
repairedUrl: string;
/** 字体列表 */
font: string[];
/** 图翻标准版特有:上传的原图地址(Pro 版放在 srcImage) */
pictUrl?: string;
/**
* 用户在编辑器内新增的贴纸 / 素材 / 文本等图层。
* textAreas 只建模算法识别出的文字区,表达不了这些图层,故单独存放。
* 算法原始返回不带该字段,用户未新增图层时也不带。
*/
editorLayers?: EditorLayer[];
}
interface Rect {
top: number;
left: number;
width: number;
height: number;
/** 旋转角度 */
degree: number;
}
interface TextArea {
/** 垂直对齐:top / center / bottom */
verticalLayout: string;
/** 水平对齐:left / center / right */
horizontalLayout: string;
/** 译文列表(按语种) */
texts: TextItem[];
color: string;
fontsize: number;
lineCount: number;
/** 原文内容 */
content: string;
}
interface TextItem {
valid: boolean;
verticalLayout: string;
horizontalLayout: string;
color: string;
/** 在图片上的位置 */
imageRect: Rect;
fontsize: number;
/** 语种 */
language: string;
/** 文字框位置 */
textRect: Rect;
/** 译文内容 */
value: string;
lineCount: number;
/** 描边颜色 */
stroke?: string;
/** 描边粗细 */
strokeWidth?: number;
/** 描边绘制顺序:stroke / fill */
paintFirst?: string;
/** 阴影 */
shadow?: Shadow;
/** 字间距 */
charSpacing?: number;
/** 文字底色 */
backgroundColor?: string;
/** 行高 */
lineHeight?: number;
/** 文字装饰:underline / line-through */
textDecoration?: string;
}
interface Shadow {
color: string;
offsetX: number;
offsetY: number;
/** 模糊度 */
blur: number;
}
interface ResultImageItem {
/** 语种 */
language: string;
/** 结果图地址 */
fileUrl: string;
}6、API 返回的图层信息
图片翻译标准版与 Pro 版 API 返回的图层结构基本一致:原图地址均在 SrcImage;标准版还通过 EditInfo.PictUrl 额外记录上传的原图地址。Data.GenFiles 在原始 API 响应中为 String,反序列化后为 Array[Object],可直接作为 reEditData 传入编辑器二次编辑(见 §4.2)。
智能消除 / 智能抠图的genFiles结构相同,只是未编辑时不含文字区(TextAreas为空),RepairedUrl为消除/抠图后的结果底图,同样可作为reEditData使用。
[*]表示数组中的任意元素。例如GenFiles[*]表示任意一项图层数据。
序号 | 参数名称 | 数据类型 | 参数描述及示例值 |
1 |
|
| 编辑器协议信息,仅当 |
2 |
|
| 原图 URL |
3 |
|
| 编辑器详细信息 |
4 |
|
| 上传的原图 URL,仅图片翻译标准版返回 |
5 |
|
| 翻译后图片的全局 ID 集合 |
6 |
|
| 所有文字涂抹后的图片 URL |
7 |
|
| 翻译语种列表 |
8 |
|
| 文本框列表 |
9 |
|
| 字体大小 |
10 |
|
| 翻译前的文本 |
11 |
|
| 文字颜色,例如 |
12 |
|
| 垂直对齐方式: |
13 |
|
| 水平对齐方式: |
14 |
|
| 文本框行数 |
15 |
|
| 翻译后文本列表 |
16 |
|
| 字体大小 |
17 |
|
| 语言 |
18 |
|
|
|
19 |
|
| 图片修复区域 |
20 |
|
| 文本框区域 |
21 |
|
| 文字颜色 |
22 |
|
| 翻译后的文本 |
23 |
|
| 垂直对齐方式 |
24 |
|
| 水平对齐方式 |
25 |
|
| 文本框行数 |
26 |
|
| 商品框区域 |
27 |
|
| 字体类型列表 |
28 |
|
| 翻译结果列表 |
29 |
|
| 翻译语种 |
30 |
|
| 翻译后的图片 URL |
7、翻译支持语向
图片翻译标准版及图片翻译Pro版支持的语向详见:语向映射
8、错误码
详见错误码
9、计费方式
计费项 | 计费单位 | 刊例价(人民币) |
文本翻译 | 每百万字符 | ¥50 |
图片翻译标准版 | 每张 | ¥0.015 |
图片翻译Pro 版 | 每张 | ¥0.06 |
智能消除标准版 | 每张 | ¥0.025 |
智能消除Pro版 | 每张 | ¥0.12 |
智能抠图 | 每张 | ¥0.002 |













































