Portrait Background Blending

Description

Blends a user-provided portrait with a reference background to generate a new portrait image. Submit one portrait image and one background image, and use media_type to identify the role of each image.

Image Examples

Portrait ImageBackground ImageOutput Image
Portrait imageBackground imageOutput image

Image Requirements

JPG and PNG are supported. Provide two images in init_images:

  • Background image: set profile.media_profiles.media_type to media_data_bg.
  • Portrait image: set profile.media_profiles.media_type to media_data_fg.

For image URLs, set media_data_type to url. For Base64-encoded images, set it to jpg. The examples submit the background image first and the portrait image second. Both images must include the appropriate role identifier.

Request URL

  • Endpoint: https://openapi.meitu.com/api/v1/sdk/sync/push
  • Task name (task): /v1/bg_portrait_replace/bg_portrait/446025
  • Task type (task_type): formula

HTTP Method

POST

Content-Type: application/json

Authentication

Sign requests using your Access Key (AK) and Secret Key (SK). See API Request Signing.

Request Parameters

RequiredParameterTypeDescription
YestaskstringFixed value: /v1/bg_portrait_replace/bg_portrait/446025.
Yestask_typestringFixed value: formula.
Yesinit_imagesobject[]Two input images: a background image and a portrait image. Identify each image's role with media_type.
YesparamsstringNo additional algorithm parameters are required. Pass the string "{}", not the JSON object {}.
Nosync_timeoutintSynchronous wait time in seconds. Default: 30. Set to -1 to return without waiting. If data.status = 9, use the Task Status API to retrieve the result.
Norsp_media_typestringOutput transmission type. Default: url for image URLs. Use jpg for Base64-encoded image data. This field belongs at the top level of the request body. The examples use the default URL output.

init_images Item

RequiredParameterTypeDescription
YesurlstringImage URL or Base64-encoded image data, matching media_data_type.
YesprofileobjectImage transmission information and role identifier.

profile

RequiredParameterTypeDescription
Yesmedia_profilesobjectImage transmission type and role.
YesversionstringFixed value: v1.

media_profiles

RequiredParameterTypeDescription
Yesmedia_data_typestringurl: image URL. jpg: Base64-encoded image data.
Yesmedia_typestringmedia_data_bg: reference background. media_data_fg: user portrait.

Request Example

This example provides the background and portrait images by URL. Replace the example image URLs with accessible URLs.

{
  "task": "/v1/bg_portrait_replace/bg_portrait/446025",
  "task_type": "formula",
  "init_images": [
    {
      "url": "https://example.com/background.jpg",
      "profile": {
        "media_profiles": {
          "media_data_type": "url",
          "media_type": "media_data_bg"
        },
        "version": "v1"
      }
    },
    {
      "url": "https://example.com/portrait.jpg",
      "profile": {
        "media_profiles": {
          "media_data_type": "url",
          "media_type": "media_data_fg"
        },
        "version": "v1"
      }
    }
  ],
  "params": "{}",
  "sync_timeout": 30
}

Response Fields

The following descriptions and examples use the default URL output. Result images are periodically deleted after 24 hours. Download and save them promptly.

FieldTypeDescription
codeintRequest processing status. 0 indicates normal request processing; a nonzero value indicates failure. Also check data.status to determine whether the task has completed.
messagestringResponse message or error information.
dataobject/nullTask information. May be null if the request fails.

data

FieldTypeDescription
statusintTask status: -1 not found; 0 created; 1 processing; 2 failed; 9 result query required; 10 succeeded.
msgstringMedia attribute description, when included in the response.
resultobjectTask ID and processing result.
progressnumberTask progress, for example 0.1, 0.85, or 1.

result

FieldTypeDescription
idstringTask ID. Pass this value as task_id when querying the result.
urlsstring[]Result image URLs available after the task succeeds.

When data.status is 9, use data.result.id to call the Task Status API. Send a signed GET request to https://openapi.meitu.com/api/v1/sdk/status?task_id=<TASK_ID>.

If the query returns status 0 or 1, the task is not yet complete. When status is 10, retrieve data.result.urls. Status 2 indicates task failure. Tasks expire after 24 hours; historical task queries are not supported.

Response Examples

Successful Response

The task has completed: data.status = 10.

{
  "code": 0,
  "message": "",
  "data": {
    "status": 10,
    "result": {
      "id": "50309bd5-a827-4125-bc96-62039c93770b",
      "urls": [
        "https://example.com/result.png"
      ]
    },
    "progress": 1
  }
}

Query-Required Response

Query the task result using data.result.id as the task_id parameter.

{
  "code": 0,
  "message": "",
  "data": {
    "status": 9,
    "result": {
      "id": "50309bd5-a827-4125-bc96-62039c93770b"
    },
    "progress": 0
  }
}

Failed Response

{
  "code": 20008,
  "message": "UNSUITABLE_IMAGE",
  "data": null
}

Error Codes

Error CodeError MessageDescription
20008UNSUITABLE_IMAGEThe image does not meet the API requirements.

For other errors, see API Error Codes.

SDK Examples

The following examples submit a portrait background blending task with the same request parameters. Replace the AK, SK, background image URL, and portrait image URL before running the code.

The examples print the API response. After a successful request, check data.status. If it is 9, query the task result as described above.

Python

Set up the SDK as described in the Python Signing SDK documentation.

import json

import requests
from sign_sdk import sign

def api_call_example():
    key = "your_access_key"
    secret = "your_secret_key"
    url = "https://openapi.meitu.com/api/v1/sdk/sync/push"
    headers = {
        "Content-Type": "application/json",
        sign.HeaderHost: "openapi.meitu.com",
    }
    payload = {
        "task": "/v1/bg_portrait_replace/bg_portrait/446025",
        "task_type": "formula",
        "init_images": [
            {
                "url": "https://example.com/background.jpg",
                "profile": {
                    "media_profiles": {
                        "media_data_type": "url",
                        "media_type": "media_data_bg"
                    },
                    "version": "v1"
                }
            },
            {
                "url": "https://example.com/portrait.jpg",
                "profile": {
                    "media_profiles": {
                        "media_data_type": "url",
                        "media_type": "media_data_fg"
                    },
                    "version": "v1"
                }
            }
        ],
        "params": "{}",
        "sync_timeout": 30
    }
    body = json.dumps(payload, ensure_ascii=False)

    signer = sign.Signer(key, secret)
    signed_request = signer.sign(url, "POST", headers, body)
    with requests.Session() as session:
        response = session.send(signed_request, timeout=60)
        print("Status:", response.status_code)
        print("Response:", response.text)

if __name__ == "__main__":
    api_call_example()

Go

Set up the SDK as described in the Go Signing SDK documentation.

package main

import (
	"fmt"
	"io"
	"net/http"
	"time"

	"github.com/mtlab/api/signer"
)

func main() {
	key := "your_access_key"
	secret := "your_secret_key"
	signObj := signer.NewSigner(key, secret)
	url := "https://openapi.meitu.com/api/v1/sdk/sync/push"
	headers := make(http.Header)
	headers.Set(signer.HeaderHost, "openapi.meitu.com")
	headers.Set("Content-Type", "application/json")

	body := `{
  "task": "/v1/bg_portrait_replace/bg_portrait/446025",
  "task_type": "formula",
  "init_images": [
    {
      "url": "https://example.com/background.jpg",
      "profile": {
        "media_profiles": {
          "media_data_type": "url",
          "media_type": "media_data_bg"
        },
        "version": "v1"
      }
    },
    {
      "url": "https://example.com/portrait.jpg",
      "profile": {
        "media_profiles": {
          "media_data_type": "url",
          "media_type": "media_data_fg"
        },
        "version": "v1"
      }
    }
  ],
  "params": "{}",
  "sync_timeout": 30
}`
	req, err := signObj.Sign(url, http.MethodPost, headers, body)
	if err != nil {
		fmt.Println("Failed to sign request:", err)
		return
	}
	client := &http.Client{Timeout: 60 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Failed to send request:", err)
		return
	}
	defer resp.Body.Close()

	responseBody, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Failed to read response:", err)
		return
	}
	fmt.Println("Status:", resp.StatusCode)
	fmt.Println("Response:", string(responseBody))
}

PHP

Set up the SDK as described in the PHP Signing SDK documentation.

<?php
require_once __DIR__ . '/signer.php';

$key = 'your_access_key';
$secret = 'your_secret_key';
$url = 'https://openapi.meitu.com/api/v1/sdk/sync/push';
$headers = [
    'Content-Type' => 'application/json',
    'Host' => 'openapi.meitu.com',
];
$body = json_encode([
    'task' => '/v1/bg_portrait_replace/bg_portrait/446025',
    'task_type' => 'formula',
    'init_images' => [
        [
            'url' => 'https://example.com/background.jpg',
            'profile' => [
                'media_profiles' => [
                    'media_data_type' => 'url',
                    'media_type' => 'media_data_bg',
                ],
                'version' => 'v1',
            ],
        ],
        [
            'url' => 'https://example.com/portrait.jpg',
            'profile' => [
                'media_profiles' => [
                    'media_data_type' => 'url',
                    'media_type' => 'media_data_fg',
                ],
                'version' => 'v1',
            ],
        ],
    ],
    'params' => '{}',
    'sync_timeout' => 30,
], JSON_UNESCAPED_SLASHES);

$signer = new Signer($key, $secret);
$curl = $signer->sign($url, 'POST', $headers, $body);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_TIMEOUT, 60);
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

Set up the SDK as described in the Java Signing SDK documentation.

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 {
        Signer signer = new Signer("your_access_key", "your_secret_key");
        String url = "https://openapi.meitu.com/api/v1/sdk/sync/push";
        String method = "POST";
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        headers.put(Signer.HeaderHost, "openapi.meitu.com");

        String body = "{\n"
                + "  \"task\": \"/v1/bg_portrait_replace/bg_portrait/446025\",\n"
                + "  \"task_type\": \"formula\",\n"
                + "  \"init_images\": [\n"
                + "    {\n"
                + "      \"url\": \"https://example.com/background.jpg\",\n"
                + "      \"profile\": {\n"
                + "        \"media_profiles\": {\n"
                + "          \"media_data_type\": \"url\",\n"
                + "          \"media_type\": \"media_data_bg\"\n"
                + "        },\n"
                + "        \"version\": \"v1\"\n"
                + "      }\n"
                + "    },\n"
                + "    {\n"
                + "      \"url\": \"https://example.com/portrait.jpg\",\n"
                + "      \"profile\": {\n"
                + "        \"media_profiles\": {\n"
                + "          \"media_data_type\": \"url\",\n"
                + "          \"media_type\": \"media_data_fg\"\n"
                + "        },\n"
                + "        \"version\": \"v1\"\n"
                + "      }\n"
                + "    }\n"
                + "  ],\n"
                + "  \"params\": \"{}\",\n"
                + "  \"sync_timeout\": 30\n"
                + "}";

        Map<String, String> signedHeaders = signer.sign(url, method, headers, body);
        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        try {
            connection.setRequestMethod(method);
            connection.setConnectTimeout(10000);
            connection.setReadTimeout(60000);
            connection.setInstanceFollowRedirects(false);
            for (Map.Entry<String, String> entry : signedHeaders.entrySet()) {
                connection.setRequestProperty(entry.getKey(), entry.getValue());
            }
            connection.setDoOutput(true);
            try (OutputStream output = connection.getOutputStream()) {
                output.write(body.getBytes(StandardCharsets.UTF_8));
            }

            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: "
                            + new String(output.toByteArray(), StandardCharsets.UTF_8));
                }
            }
        } finally {
            connection.disconnect();
        }
    }
}