白板涂鸦 v3
描述
根据输入的涂鸦图片生成指定风格的图片。支持设置涂鸦背景类型、生成风格、是否扩展画面以及输出尺寸。
版本
1.0
图片要求
支持 JPG、PNG 格式,可通过图片 URL 或 Base64 编码传入。
调用 URL
- 正式环境:`https://openapi.meitu.com`
- 任务提交接口:`https://openapi.meitu.com/api/v1/sdk/sync/push`
- 任务名称(`task`):`/v1/AI_Drawing_White_V3/426943`
- 任务类型(`task_type`):`formula`调用方法
POST
Content-Type: application/json
权限
使用 Access Key(AK)和 Secret Key(SK)进行请求签名,详见开放平台接口签名。
Credits 不能用于 API 接口扣费。开通功能及资源包购买与管理请前往 MV 控制台。
请求参数
| 是否必选 | 参数名 | 类型 | 参数说明 |
|---|---|---|---|
| 必选 | task | string | 固定为 /v1/AI_Drawing_White_V3/426943。 |
| 必选 | task_type | string | 固定为 formula。 |
| 必选 | init_images | object[] | 输入涂鸦图片列表。 |
| 必选 | params | string | 算法参数的 JSON 字符串,解码后的字段见下文。 |
| 可选 | sync_timeout | int | 同步等待超时时间,单位为秒,默认 30。超时后通过任务查询接口获取结果。 |
init_images 元素
| 是否必选 | 参数名 | 类型 | 参数说明 |
|---|---|---|---|
| 必选 | url | string | 图片 URL 或 Base64 编码数据。URL 地址不进行 Base64 编码。 |
| 必选 | profile | object | 图片属性信息。 |
profile
| 是否必选 | 参数名 | 类型 | 参数说明 |
|---|---|---|---|
| 必选 | media_profiles | object | 图片传输信息。 |
| 必选 | version | string | 固定为 v1。 |
| 可选 | media_extra | object | 图片附加信息,无附加信息时可传 {}。 |
media_profiles
| 是否必选 | 参数名 | 类型 | 参数说明 |
|---|---|---|---|
| 必选 | media_data_type | string | url 表示图片 URL;jpg 表示 Base64 编码数据。请根据输入方式显式填写;算法默认值为 jpg。 |
params
以下字段直接位于 params 解码后的对象中。先序列化该对象,再将得到的字符串赋给请求体的 params。
| 是否必选 | 参数名 | 类型 | 参数说明 |
|---|---|---|---|
| 必选 | scribble_bg_type | int | 涂鸦背景类型:0 为白底,1 为黑底。算法默认黑底,调用时请显式传入。 |
| 必选 | scribble_style_type | string | 生成风格标识。可用值请咨询商务,不能直接使用示例占位值 YOUR_STYLE_ID。 |
| 可选 | padding_type | int | 是否扩展画面:0 不扩展,1 扩展,默认 0。 |
| 可选 | height | int | 输出高度,单位为像素,范围 [100, 2048],推荐 1024。优先级高于输入图片高度。 |
| 可选 | width | int | 输出宽度,单位为像素,范围 [100, 2048],推荐 1024。优先级高于输入图片宽度。 |
输入值示例
以下示例使用白底涂鸦,不扩展画面,输出尺寸为 1024 × 1024。调用前替换图片 URL 和 YOUR_STYLE_ID。
{
"task": "/v1/AI_Drawing_White_V3/426943",
"task_type": "formula",
"init_images": [
{
"url": "https://example.com/input.png",
"profile": {
"media_profiles": {
"media_data_type": "url"
},
"version": "v1"
}
}
],
"params": "{\"scribble_bg_type\":0,\"scribble_style_type\":\"YOUR_STYLE_ID\",\"padding_type\":0,\"height\":1024,\"width\":1024}",
"sync_timeout": 30
}返回值说明
注意,生成的结果会定期清理,请及时下载保存。成功响应从 data.result.urls 读取结果图片地址。HTTP 请求成功不代表任务完成,还需检查 data.status。
成功返回字段
| 字段 | 类型 | 说明 |
|---|---|---|
| error_code | int | 错误码,0 表示请求正常。 |
| message | string | 响应消息。 |
| data | object | 任务状态、进度和结果。 |
data
| 字段 | 类型 | 说明 |
|---|---|---|
| status | int | 任务状态:-1 未找到;0 创建成功;1 执行中;2 失败;9 同步等待超时,需查询;10 成功。 |
| result | object | 任务标识与结果。 |
| progress | number | 任务进度,例如 0.1、0.85、1。 |
result
| 字段 | 类型 | 说明 |
|---|---|---|
| id | string | 网关任务 ID,查询任务时作为 task_id 传入。 |
| urls | string[] | 任务成功后的结果图片 URL 列表。 |
失败返回字段
| 字段 | 类型 | 说明 |
|---|---|---|
| ErrorCode | int | 错误码。 |
| ErrorMsg | string | 错误信息。 |
| Data | string/null | 错误详情;下方示例为 null。 |
失败示例中的字段名区分大小写,请保留 ErrorCode、ErrorMsg 和 Data 的原始拼写。
返回值示例
请求成功返回示例
Response Status: 200
Content-Type: application/json; charset=utf-8
{
"error_code": 0,
"message": "success",
"data": {
"status": 10,
"result": {
"id": "example-task-id",
"urls": [
"https://example.com/result.jpeg"
]
},
"progress": 1
}
}需要查询时
当返回 data.status = 9 时,同步等待已经超时,不代表任务失败。使用任务 ID 按任务查询接口查询结果。
本接口已说明的任务 ID 字段为 data.result.id。查询返回 0 或 1 时任务尚未完成,10 为成功,2 为失败。
请求失败返回示例
Response Status: 400
Content-Type: application/json; charset=utf-8
{
"ErrorCode": 20001,
"ErrorMsg": "PROCESS_ERROR",
"Data": null
}当前 API 特有的错误代码与信息
| 错误码 | 错误信息 | 说明 |
|---|---|---|
| 20001 | PROCESS_ERROR | 处理错误。 |
| 20014 | NOT_FOUND | 未找到图片。 |
| 20008 | UNSUITABLE_IMAGE | 图片不符合要求。 |
| 20026 | NO_SUCH_MODE | 指定模式不存在。 |
| 20034 | NO_SUCH_STYLE | 指定风格不存在。 |
| 21008 | BACKGROUND_IMAGE_LOSS | 缺少背景图片。 |
| 20025 | INIT_FAIL | 初始化失败。 |
| 21021 | MASK_LOSS | 缺少 mask。 |
| 21022 | SKETCH_LOSS | 缺少 sketch。 |
通用的错误代码与信息
详见 API 错误码。
SDK 调用示例
以下示例均使用上方请求参数。调用前替换 AK、SK、图片 URL 和 YOUR_STYLE_ID,并按对应语言的接入文档引入签名 SDK。
示例打印响应;任务未完成时,按任务查询接口获取结果。
Python
import json
import requests
from sign_sdk import sign
def main():
key = "YOUR_ACCESS_KEY"
secret = "YOUR_SECRET_KEY"
url = "https://openapi.meitu.com/api/v1/sdk/sync/push"
params = {
"scribble_bg_type": 0,
"scribble_style_type": "YOUR_STYLE_ID",
"padding_type": 0,
"height": 1024,
"width": 1024
}
payload = {
"task": "/v1/AI_Drawing_White_V3/426943",
"task_type": "formula",
"init_images": [{
"url": "https://example.com/input.png",
"profile": {
"media_profiles": {"media_data_type": "url"},
"version": "v1",
},
}],
"params": json.dumps(params, ensure_ascii=True),
"sync_timeout": 30,
}
body = json.dumps(payload, ensure_ascii=True)
headers = {
"Content-Type": "application/json",
sign.HeaderHost: "openapi.meitu.com",
}
signer = sign.Signer(key, secret)
signed_request = signer.sign(url, "POST", headers, body)
with requests.Session() as session:
response = session.send(
signed_request, timeout=(10, 60), verify=True, allow_redirects=False
)
print("Status:", response.status_code)
print("Response:", response.text)
if __name__ == "__main__":
main()Go
package main
import (
"fmt"
"io"
"net/http"
"time"
"github.com/mtlab/api/signer"
)
func main() {
url := "https://openapi.meitu.com/api/v1/sdk/sync/push"
body := `{
"task": "/v1/AI_Drawing_White_V3/426943",
"task_type": "formula",
"init_images": [
{
"url": "https://example.com/input.png",
"profile": {
"media_profiles": {
"media_data_type": "url"
},
"version": "v1"
}
}
],
"params": "{\"scribble_bg_type\":0,\"scribble_style_type\":\"YOUR_STYLE_ID\",\"padding_type\":0,\"height\":1024,\"width\":1024}",
"sync_timeout": 30
}`
headers := make(http.Header)
headers.Set("Content-Type", "application/json")
headers.Set(signer.HeaderHost, "openapi.meitu.com")
signObj := signer.NewSigner("YOUR_ACCESS_KEY", "YOUR_SECRET_KEY")
req, err := signObj.Sign(url, http.MethodPost, headers, body)
if err != nil {
fmt.Println("Sign request failed:", err)
return
}
client := &http.Client{
Timeout: 60 * time.Second,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
resp, err := client.Do(req)
if err != nil {
fmt.Println("Send request failed:", err)
return
}
defer resp.Body.Close()
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Read response failed:", err)
return
}
fmt.Println("Status:", resp.StatusCode)
fmt.Println("Response:", string(responseBody))
}PHP
<?php
require_once __DIR__ . '/signer.php';
$params = json_encode([
'scribble_bg_type' => 0,
'scribble_style_type' => 'YOUR_STYLE_ID',
'padding_type' => 0,
'height' => 1024,
'width' => 1024,
]);
$body = json_encode([
'task' => '/v1/AI_Drawing_White_V3/426943',
'task_type' => 'formula',
'init_images' => [[
'url' => 'https://example.com/input.png',
'profile' => [
'media_profiles' => ['media_data_type' => 'url'],
'version' => 'v1',
],
]],
'params' => $params,
'sync_timeout' => 30,
], JSON_UNESCAPED_SLASHES);
$url = 'https://openapi.meitu.com/api/v1/sdk/sync/push';
$headers = [
'Content-Type' => 'application/json',
'Host' => 'openapi.meitu.com',
];
$signer = new Signer('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY');
$curl = $signer->sign($url, 'POST', $headers, $body);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($curl, CURLOPT_TIMEOUT, 60);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
$response = curl_exec($curl);
if ($response === false) {
echo 'Error: ' . curl_error($curl) . PHP_EOL;
} else {
echo 'Status: ' . curl_getinfo($curl, CURLINFO_HTTP_CODE) . PHP_EOL;
echo 'Response: ' . $response . PHP_EOL;
}
curl_close($curl);Java
import com.meitu.openai.common.Signer;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) throws Exception {
String body =
"{\n" +
" \"task\": \"/v1/AI_Drawing_White_V3/426943\",\n" +
" \"task_type\": \"formula\",\n" +
" \"init_images\": [\n" +
" {\n" +
" \"url\": \"https://example.com/input.png\",\n" +
" \"profile\": {\n" +
" \"media_profiles\": {\n" +
" \"media_data_type\": \"url\"\n" +
" },\n" +
" \"version\": \"v1\"\n" +
" }\n" +
" }\n" +
" ],\n" +
" \"params\": \"{\\\"scribble_bg_type\\\":0,\\\"scribble_style_type\\\":\\\"YOUR_STYLE_ID\\\",\\\"padding_type\\\":0,\\\"height\\\":1024,\\\"width\\\":1024}\",\n" +
" \"sync_timeout\": 30\n" +
"}";
String url = "https://openapi.meitu.com/api/v1/sdk/sync/push";
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
headers.put(Signer.HeaderHost, "openapi.meitu.com");
Signer signer = new Signer("YOUR_ACCESS_KEY", "YOUR_SECRET_KEY");
Map<String, String> signedHeaders = signer.sign(url, "POST", headers, body);
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
try {
connection.setRequestMethod("POST");
connection.setConnectTimeout(10000);
connection.setReadTimeout(60000);
connection.setInstanceFollowRedirects(false);
connection.setDoOutput(true);
for (Map.Entry<String, String> entry : signedHeaders.entrySet()) {
connection.setRequestProperty(entry.getKey(), entry.getValue());
}
byte[] bodyBytes = body.getBytes(StandardCharsets.UTF_8);
connection.setFixedLengthStreamingMode(bodyBytes.length);
try (OutputStream output = connection.getOutputStream()) {
output.write(bodyBytes);
}
int status = connection.getResponseCode();
System.out.println("Status: " + status);
InputStream stream = status >= 400
? connection.getErrorStream() : connection.getInputStream();
if (stream != null) {
try (InputStream input = stream;
ByteArrayOutputStream output = new ByteArrayOutputStream()) {
byte[] buffer = new byte[4096];
int length;
while ((length = input.read(buffer)) != -1) {
output.write(buffer, 0, length);
}
System.out.println("Response: " + output.toString("UTF-8"));
}
}
} finally {
connection.disconnect();
}
}
}