---
title: "이미지 번역"
description: "상품 이미지 속 텍스트를 원본 시각 스타일(자형 굵기 · 색상 · 레이아웃 · 배지 배경)을 유지한 채 다른 언어로 치환합니다."
---

## 엔드포인트

```
POST /v1/image-translate/translate
```

상품 이미지를 **원시 바이트(raw binary)** 로 전송하면, 원본 텍스트가 지워지고 선택한 대상 언어로 치환된 이미지를 반환합니다. 폰트 · 굵기 · 렌더 모드는 호출자가 쿼리 스트링으로 지정합니다.

- **입력 언어** — 중국어(간체 또는 번체), 일본어, 영어. `auto` 를 보내면 스크립트 필터를 건너뜁니다.
- **출력 언어** — ISO-639 형식의 임의 코드. 시각 품질은 선택한 `font` 가 해당 스크립트의 글리프를 가지고 있는지에 달려 있습니다. 한국어 · 중국어 간체 · 일본어 · 라틴 계열이 1순위 지원이며, 실시간 폰트 · 원본 언어 코드 목록은 [`/supported-fonts`](./supported-fonts) 에서 확인하세요.

## 요청 형식

엔드포인트는 HTTP body에 **원시 이미지 바이트** 만 받습니다. JSON + base64는 허용되지 않습니다.

| 헤더 | 필수 | 비고 |
|---|---|---|
| `Content-Type` | 예 | `image/jpeg`, `image/png`, `image/webp`, 또는 `application/octet-stream` |
| `x-api-key` | 예 | API 키 |

이외의 모든 파라미터는 **쿼리 스트링** 으로 전달합니다.

| 파라미터 | 타입 | 필수 | 기본값 | 설명 |
|-----------|------|------|--------|-----|
| `source_language` | string | 예 | — | `ch`, `zh`, `zh-CN`, `zh-TW`, `chinese_cht`, `ja`, `japan`, `en`, `auto` 중 하나. `auto` 는 스크립트 필터를 끄고 번역이 있는 모든 영역을 렌더합니다. |
| `target_language` | string (2–8자) | 예 | — | ISO-639 형식의 대상 언어 코드. 자유 입력. |
| `font` | string | 아니오 | `Pretendard` | [`/supported-fonts`](./supported-fonts) 의 `allFonts` 중 하나. ASCII 외 문자가 포함된 경우 URL 인코딩하세요. **기본값은 `Pretendard`** — 한글, CJK 구두점(×, （ ）, 《 》, · 등), Latin Extended-A 까지 모두 커버하는 가변 굵기 한글 산세리프입니다. 렌더러가 내장 fallback chain 을 돌리기 때문에, 선택한 폰트가 갖지 못한 글리프(예: 한자)는 `Pretendard` → `NotoSansSC` 순서로 자동으로 채워집니다. |
| `font_weight` | string | 아니오 | `ExtraBold` | `auto`, `Thin`, `Light`, `Regular`, `Medium`, `SemiBold`, `Bold`, `ExtraBold`, `Black` 중 하나. |
| `render` | boolean | 아니오 | `true` | `true` 는 최종 번역 이미지(바이너리) 반환. `false` 는 텍스트가 지워진 이미지와 영역별 메타데이터를 JSON 으로 반환합니다. |

## 응답

### `render=true` (기본) — 바이너리 이미지

`render=true` 일 때 응답 body는 **렌더된 JPEG 바이트** 이며 `Content-Type: image/jpeg` 입니다. 메타데이터는 응답 헤더로 전달됩니다.

| 헤더 | 설명 |
|---|---|
| `X-Apinoa-Request-Id` | 요청 ID (이슈 신고 시 인용하세요) |
| `X-Apinoa-Regions-Count` | 감지/치환된 텍스트 영역 수 |

텍스트가 감지되지 않은 경우 응답 body는 원본 이미지 바이트이고 `X-Apinoa-Regions-Count: 0` 입니다.

### `render=false` — JSON + 영역 정보

`render=false` 일 때 응답은 JSON 입니다.

```json
{
  "success": true,
  "requestId": "550e8400e29b41d4a716446655440000",
  "data": {
    "inpainted_base64": "<텍스트 제거된 이미지의 base64 JPEG>",
    "regions": [
      {
        "polygon": [[10, 20], [210, 20], [210, 60], [10, 60]],
        "bbox": { "x": 10, "y": 20, "w": 200, "h": 40 },
        "text": "免费送货",
        "text_kr": "무료 배송",
        "confidence": 0.98,
        "text_color": { "r": 255, "g": 255, "b": 255 },
        "bg_color": { "r": 200, "g": 50, "b": 50 },
        "font_weight": "Bold",
        "is_badge": true
      }
    ],
    "regions_count": 5
  }
}
```

| 필드 | 타입 | 설명 |
|-------|------|-----|
| `inpainted_base64` | string | 원본 텍스트가 제거된 base64 JPEG |
| `regions[].polygon` | number[][] | 원본 좌표계의 4점 폴리곤 |
| `regions[].bbox` | object | 원본 좌표계의 축정렬 경계 박스 |
| `regions[].text` | string | 인식된 원문 |
| `regions[].text_kr` | string | 요청한 `target_language` 의 번역문. |
| `regions[].confidence` | number | 인식 신뢰도, 0–1 |
| `regions[].text_color` / `bg_color` | object | RGB 색상 추정 |
| `regions[].font_weight` | string | 감지된 굵기: `Thin`, `Regular`, `Bold` |
| `regions[].is_badge` | boolean | 가격표 · 세일 배지 같은 채워진 사각 라벨이면 `true` |

## 예제

### 기본 번역 (cURL)

```bash
curl -X POST "https://gateway.apinoa.com/v1/image-translate/translate?source_language=zh-CN&target_language=ko" \
  -H "x-api-key: $APINOA_API_KEY" \
  -H "Content-Type: image/jpeg" \
  --data-binary @product.jpg \
  -o translated.jpg
```

### 폰트 지정 (Python)

```python
import requests

with open("product.jpg", "rb") as f:
    img_bytes = f.read()

r = requests.post(
    "https://gateway.apinoa.com/v1/image-translate/translate",
    headers={
        "x-api-key": "YOUR_API_KEY",
        "Content-Type": "image/jpeg",
    },
    params={
        "source_language": "zh-CN",
        "target_language": "ko",
        "font": "Pretendard",
        "font_weight": "Bold",
    },
    data=img_bytes,
    timeout=300,  # 서버 타임아웃은 5분 — 아래 "타임아웃" 섹션 참고
)
r.raise_for_status()
with open("translated.jpg", "wb") as f:
    f.write(r.content)
print("regions:", r.headers.get("X-Apinoa-Regions-Count"))
```

### 인페인트만 받아 클라이언트에서 렌더 (Node.js / TypeScript)

```typescript
import { readFileSync, writeFileSync } from "node:fs";

const image = readFileSync("product.jpg");

const url = new URL("https://gateway.apinoa.com/v1/image-translate/translate");
url.searchParams.set("source_language", "zh-CN");
url.searchParams.set("target_language", "ko");
url.searchParams.set("render", "false");

const res = await fetch(url, {
  method: "POST",
  headers: {
    "x-api-key": process.env.APINOA_API_KEY!,
    "Content-Type": "image/jpeg",
  },
  body: image,
});

const { data } = (await res.json()) as {
  data: { inpainted_base64: string; regions: any[] };
};
writeFileSync("inpainted.jpg", Buffer.from(data.inpainted_base64, "base64"));
```

## 제한

| 항목 | 값 |
|-------|-------|
| 최대 이미지 크기 | 8192 × 8192 px |
| 최대 요청 본문 | 20 MB |
| API 키별 QPS | 플랜의 초당 한도와 동일 |
| 이미지 포맷 | JPEG, PNG, WebP |

크기 초과 이미지는 `413 Payload Too Large` 를, QPS 초과는 `retry-after` 가 포함된 `429 Too Many Requests` 를 반환합니다.

## 오류

| 코드 | HTTP | 발생 조건 | 대응 |
|------|------|------|------------|
| `BAD_REQUEST` | 400 | 빈 본문 또는 잘못된 쿼리 파라미터 | 요청 형식을 점검 |
| `UNAUTHORIZED` | 401 | API 키 누락 또는 무효 | `x-api-key` 헤더 확인 |
| `UNSUPPORTED_MEDIA_TYPE` | 415 | `Content-Type` 이 바이너리 이미지 형식이 아님 | `Content-Type: image/jpeg` (또는 png/webp) 로 원시 바이트 전송 |
| `PAYLOAD_TOO_LARGE` | 413 | 본문 > 20 MB | 클라이언트에서 다운스케일 |
| `INSUFFICIENT_BALANCE` | 402 | 잔액이 호출 비용에 못 미침 | **대시보드 > 잔액**에서 충전; 재시도로는 해결되지 않음 |
| `UPSTREAM_ERROR` | 502 | 처리 일시 불가 | 재시도; 보통 60초 이내 회복 |
| `SERVICE_UNAVAILABLE` | 503 | 일시적 용량 초과 | 백오프 후 재시도 |

## 타임아웃

부하가 높을 때는 요청 하나가 최대 **5분(300초)** 까지 걸릴 수 있습니다. 느린 응답이 클라이언트 측에서 중단되지 않도록 HTTP 클라이언트의 타임아웃을 **최소 300초** 이상으로 설정하세요.

| 지연 | 일반적 | 최악 |
|---|---|---|
| 일반 부하 | 1.5 – 3 s | < 10 s |
| 높은 부하 | 5 – 30 s | 5 분 |

대부분의 요청은 수 초 이내에 완료됩니다. 5분 한도는 지속적인 버스트 트래픽 환경에서만 의미가 있습니다. 5분 한도에 자주 근접한다면 동시성을 낮추거나 지원팀에 문의하세요.

## 가격

각 호출은 [요금 페이지](/pricing)에 안내된 image-translate 단가로 잔액에서 차감됩니다.

## 지원

5xx 오류가 반복되거나 품질 회귀가 명확히 보이면 `X-Apinoa-Request-Id` 응답 헤더의 값을 첨부해 [apinoa.com/contact](/contact) 에서 문의하세요.
