# gpt-image-2 图像生成与编辑

QCode.cc 提供 **OpenAI 完全兼容**的 `gpt-image-2` API，覆盖两个端点：

- **文生图** `POST /v1/images/generations` — JSON 请求，纯文本生成图像
- **图像编辑** `POST /v1/images/edits` — multipart 上传 1-8 张源图（可选 mask），按 prompt 重绘 / 修改 / 多图融合（2026 年 5 月上线）

`gpt-image-2` 是 OpenAI 于 2026 年 4 月发布的最新图像模型，**文字渲染是目前所有公开图像模型里最强的**（中英文字符都可以稳定画在图里）。

QCode.cc 接入特性：

- **OpenAI SDK 零改动**：仅替换 `base_url`，请求 / 响应格式 100% 一致（含 multipart edits 接口）
- **多区域接入**：HK / 日本 / 美国 / 欧洲，按你所在网络环境就近选择
- **API Key 统一**：复用你已有的 QCode.cc `cr_` 开头密钥，与 Claude Code / Codex / Gemini CLI 同一份配额账户
- **后台用量统一**：图像调用与对话调用合并显示在客户后台 Dashboard，并提供独立自助查询页
- **两端点共享配额**：`generations` 和 `edits` 共用每个 API Key 每日 100 张上限与 2 并发上限

典型场景：海报生成、配图、产品图、UI mockup、社交媒体素材、**图像编辑（局部修改 / 多图融合 / 抠图换背景 / 高保真重绘）**。

---

## 快速开始

### 文生图（generations）

3 行 Python 完成第一张图：

```python
from openai import OpenAI
import base64

client = OpenAI(
    base_url="https://api.qcode.cc/qcode-img/v1",
    api_key="cr_YOUR_QCODE_API_KEY",
    timeout=180.0,  # 单图 30-120s，至少设 180s
)

result = client.images.generate(
    model="gpt-image-2",
    prompt="A cyberpunk Tokyo street at night, neon reflecting in rain puddles",
    size="1024x1024",
    quality="low",
    n=1,
)

with open("output.png", "wb") as f:
    f.write(base64.b64decode(result.data[0].b64_json))
```

### 图像编辑（edits）

上传现有图片 + prompt，可选 mask 做局部重绘：

```python
from openai import OpenAI
import base64

client = OpenAI(
    base_url="https://api.qcode.cc/qcode-img/v1",
    api_key="cr_YOUR_QCODE_API_KEY",
    timeout=180.0,
)

result = client.images.edit(
    model="gpt-image-2",
    image=open("cat.png", "rb"),
    mask=open("mask.png", "rb"),          # 可选：PNG alpha，透明区域是要重绘的部分
    prompt="put a tiny crown on the cat",
    size="1024x1024",
    quality="high",
)

with open("edited.png", "wb") as f:
    f.write(base64.b64decode(result.data[0].b64_json))
```

> ⚠️ **必须显式设置 timeout ≥ 180s**：OpenAI SDK 默认超时较短，gpt-image-2 推理时间显著长于传统文生图（详见下方 [生成耗时](#生成耗时与超时设置)）。

---

## 接入入口

`gpt-image-2` 服务（`generations` + `edits` 通用）在 QCode.cc 的所有接入域上都可用，只需把 `{base}` 拼成 `{base}/qcode-img/v1`：

| 用户位置 | 推荐 base_url | 协议 | 备注 |
|---|---|---|---|
| 中国大陆（HTTPS 必需）| `https://api.qcode.cc/qcode-img/v1` | HTTPS | 经全球 CDN，但 medium / high 可能触发 524（见 [CDN 100s 硬限](#cdn-100s-硬限-524-错误)）|
| 香港 / 东南亚 | `https://asia.qcode.cc/qcode-img/v1` | HTTPS | 亚洲节点（HK/JP 就近） |
| 欧洲 | `https://eu.qcode.cc/qcode-img/v1` | HTTPS | 法兰克福节点 |
| 北美 | `https://us.qcode.cc/qcode-img/v1` | HTTPS | 洛杉矶节点 |

所有入口路由到同一计费体系，用量与额度统一。完整接入域说明参见 [接入点与 API 格式](/docs/getting-started/endpoints-and-api-paths)。

> `qcode-img` 是图像生成与编辑专属路径前缀，与 Anthropic 协议的 `/api`、OpenAI 协议的 `/openai/v1`、Gemini 协议的 `/gemini` 平行。

---

## API 规范

### 通用请求头

| Header | 必需 | 值 |
|---|---|---|
| `Authorization` | ✓ | `Bearer cr_xxxxxxxxxxxxxxxx`（你的 QCode.cc API Key）|
| `Content-Type` | ✓ | `application/json`（generations）<br/>`multipart/form-data`（edits）|

### 生成接口 `/v1/images/generations`

**端点**：`POST {base_url}/images/generations`
**Content-Type**：`application/json`

请求体：

```json
{
  "model": "gpt-image-2",
  "prompt": "A small ceramic vase with sunflower, photorealistic",
  "size": "1024x1024",
  "quality": "low",
  "n": 1
}
```

字段：

| 字段 | 类型 | 必需 | 默认 | 取值 |
|---|---|---|---|---|
| `model` | string | ✓ | — | 固定 `gpt-image-2` |
| `prompt` | string | ✓ | — | 图像描述，**支持中英多语言** |
| `size` | string | ✗ | `1024x1024` | `1024x1024`（方）/ `1024x1536`（竖）/ `1536x1024`（横）|
| `quality` | string | ✗ | `medium` | `low` / `medium` / `high` |
| `n` | integer | ✗ | 1 | 单次生成数（1 – 4）；**> 4 返回 400**（不会静默截断） |

### 图像编辑接口 `/v1/images/edits`

**端点**：`POST {base_url}/images/edits`
**Content-Type**：`multipart/form-data`（上传文件用 form-data，不能用 JSON）

字段：

| 字段 | 类型 | 必需 | 默认 | 取值 / 说明 |
|---|---|---|---|---|
| `model` | string | ✓ | — | 固定 `gpt-image-2` |
| `image` | file（× N）| ✓ | — | 源图（PNG / JPEG / WebP）；**支持 1 – 8 张多图融合**（多张时重复同名字段：`-F image=@a.png -F image=@b.png`） |
| `mask` | file | ✗ | — | PNG alpha 蒙版，**透明区域**是要重绘的部分；mask 像素分辨率需与 `image` 一致（系统会自动缩放）；仅对单图有意义 |
| `prompt` | string | ✓ | — | 编辑指令（中英多语言）|
| `size` | string | ✗ | `auto` | `auto` / `1024x1024` / `1024x1536` / `1536x1024` / `2048x2048`。**输出分辨率由模型自适应决定（当前实测约 1254×1254），`size` 作为意图提示**；非法值返回 422 |
| `quality` | string | ✗ | `auto` | `auto` / `low` / `medium` / `high` |
| `n` | integer | ✗ | 1 | 单次生成数（1 – 4）；**> 4 返回 400**（不会静默截断） |
| `background` | string | ✗ | `auto` | `auto` / `opaque`。**gpt-image-2 不支持 `transparent`**（模型无法生成 alpha 通道，传入返回 400） |
| `output_format` | string | ✗ | `png` | `png` / `jpeg` / `webp` |
| `output_compression` | integer | ✗ | — | `0 – 100`，对 JPEG / WebP 生效（PNG 忽略）；**越界返回 400** |
| `input_fidelity` | string | ✗ | — | **已废弃**：gpt-image-2 恒以高保真处理输入图；传入会被忽略，不再转发到上游 |
| `response_format` | string | ✗ | `b64_json` | 仅接受 `b64_json`（传 `url` 返回 400） |
| `user` | string | ✗ | — | 终端用户 ID 透传（用于上游 abuse 检测）|

**上传体积上限**：单文件 ≤ 25 MB；多文件合计 ≤ 200 MB（超过返 `413 image_too_large`）。

### 响应（两端点格式相同）

```json
{
  "created": 1777135432,
  "data": [
    {
      "b64_json": "iVBORw0KGgo...(base64 PNG/JPEG/WebP, 1-3 MB)",
      "revised_prompt": "A small ceramic vase with sunflower..."
    }
  ]
}
```

- `b64_json`：图片的 base64 编码数据，前端可直接 `<img src="data:image/<format>;base64,...">` 渲染
- `revised_prompt`：模型对原始 prompt 的优化版本（可选展示给用户参考）

### 错误响应

错误响应符合 OpenAI 标准 schema：

```json
{
  "error": {
    "type": "rate_limit_error",
    "code": "image_daily_limit",
    "message": "Daily image generation count limit reached..."
  }
}
```

| HTTP | code | 含义 |
|---|---|---|
| 401 | `invalid_api_key` | API Key 无效或已禁用 |
| 401 | `key_expired` | API Key 已过期 |
| 413 | `image_too_large` | 上传单文件 > 25 MB，或多文件合计 > 200 MB |
| 422 | `unsupported_size` | size 不支持（合法值见各接口参数表）|
| 429 | `crs_daily_exhausted` | 你的账户当日预算已用尽 |
| 429 | `crs_total_exhausted` | 你的账户累计预算已用尽 |
| 429 | `image_daily_limit` | 每个 API Key 每日 100 张上限达到（generations + edits 共用，可申请提升）|
| 429 | `concurrency_exhausted` | 每个 API Key 并发上限 2（默认值，可申请提升）|
| 503 | `service_overloaded` | 服务全局负载过高，请稍后重试 |
| 503 | `image_provider_unavailable` | 上游暂时不可用，请稍后重试 |

---

## 代码示例

### Python（OpenAI SDK，推荐）

**文生图：**

```python
from openai import OpenAI
import base64

client = OpenAI(
    base_url="https://api.qcode.cc/qcode-img/v1",
    api_key="cr_YOUR_QCODE_API_KEY",
    timeout=180.0,
)

result = client.images.generate(
    model="gpt-image-2",
    prompt="A cyberpunk Tokyo street at night, neon reflecting in rain puddles",
    size="1024x1024",
    quality="low",
    n=1,
)

img_bytes = base64.b64decode(result.data[0].b64_json)
with open("output.png", "wb") as f:
    f.write(img_bytes)
print("已保存 output.png")
```

**图像编辑（单图 + mask 局部重绘）：**

```python
from openai import OpenAI
import base64

client = OpenAI(
    base_url="https://api.qcode.cc/qcode-img/v1",
    api_key="cr_YOUR_QCODE_API_KEY",
    timeout=180.0,
)

result = client.images.edit(
    model="gpt-image-2",
    image=open("cat.png", "rb"),
    mask=open("mask.png", "rb"),
    prompt="put a tiny crown on the cat",
    size="1024x1024",
    quality="high",
    extra_body={"output_format": "png"},
)

img = base64.b64decode(result.data[0].b64_json)
with open("edited.png", "wb") as f:
    f.write(img)
```

**图像编辑（多图融合，2 – 8 张）：**

```python
result = client.images.edit(
    model="gpt-image-2",
    image=[
        open("scene.png", "rb"),       # 第一张：场景背景
        open("product.png", "rb"),     # 第二张：要植入的产品
    ],
    prompt="Place the product naturally into the scene, match the lighting and shadows.",
    size="1536x1024",
    quality="high",
)
```

### curl

**文生图：**

```bash
curl https://api.qcode.cc/qcode-img/v1/images/generations \
  -H "Authorization: Bearer cr_YOUR_QCODE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2",
    "prompt": "A cyberpunk Tokyo street at night",
    "size": "1024x1024",
    "quality": "low",
    "n": 1
  }' \
  | jq -r ".data[0].b64_json" | base64 -d > output.png
```

**图像编辑：**

```bash
curl https://api.qcode.cc/qcode-img/v1/images/edits \
  -H "Authorization: Bearer cr_YOUR_QCODE_API_KEY" \
  -F "model=gpt-image-2" \
  -F "image=@cat.png" \
  -F "mask=@mask.png" \
  -F "prompt=put a tiny crown on the cat" \
  -F "size=1024x1024" \
  -F "quality=high" \
  -F "output_format=png" \
  | jq -r ".data[0].b64_json" | base64 -d > edited.png
```

**多图融合（重复 `-F image=@` 即可）：**

```bash
curl https://api.qcode.cc/qcode-img/v1/images/edits \
  -H "Authorization: Bearer cr_YOUR_QCODE_API_KEY" \
  -F "model=gpt-image-2" \
  -F "image=@scene.png" \
  -F "image=@product.png" \
  -F "prompt=Place the product naturally into the scene" \
  -F "size=1536x1024" \
  -F "quality=high"
```

### JavaScript / Node.js / 浏览器

**文生图：**

```javascript
const r = await fetch("https://api.qcode.cc/qcode-img/v1/images/generations", {
  method: "POST",
  headers: {
    "Authorization": "Bearer cr_YOUR_QCODE_API_KEY",
    "Content-Type":  "application/json",
  },
  body: JSON.stringify({
    model: "gpt-image-2",
    prompt: "A cyberpunk Tokyo street at night",
    size: "1024x1024",
    quality: "low",
    n: 1,
  }),
});
const json = await r.json();
const dataUrl = "data:image/png;base64," + json.data[0].b64_json;
document.querySelector("img").src = dataUrl;
```

**图像编辑（浏览器 FormData）：**

```javascript
const fd = new FormData();
fd.append("model", "gpt-image-2");
fd.append("image", imageFile);              // File 对象，来自 <input type="file">
fd.append("mask", maskFile);                // 可选
fd.append("prompt", "put a tiny crown on the cat");
fd.append("size", "1024x1024");
fd.append("quality", "high");
fd.append("output_format", "png");

const r = await fetch("https://api.qcode.cc/qcode-img/v1/images/edits", {
  method: "POST",
  headers: { "Authorization": "Bearer cr_YOUR_QCODE_API_KEY" },
  // 不要手动设 Content-Type — FormData 会自动加上含 boundary 的 multipart/form-data
  body: fd,
});
const json = await r.json();
const dataUrl = "data:image/png;base64," + json.data[0].b64_json;
document.querySelector("img").src = dataUrl;
```

---

## 限额规则

### 默认限额

| 维度 | 默认值 | 说明 |
|---|---|---|
| **每日图片数** | 100 张 / 天 / Key | 北京时间 0 点重置；**generations + edits 共用此上限** |
| **并发数** | 2 同时进行中 | 超出返 429 `concurrency_exhausted`；generations + edits 共用 |
| **上传体积**（仅 edits）| 单文件 25 MB / 多文件合计 200 MB | 超出返 413 `image_too_large` |
| **账户预算** | 共用 QCode.cc 账户的 `dailyCostLimit` / `totalCostLimit` | 超出返 429 `crs_daily_exhausted` |

默认限额对绝大多数用户充足。如需提升请联系客服。

### 用量查询

- **客户后台 Dashboard**：与 chat 调用统一展示（最近使用时间、当日费用、累计费用、模型分布）
- **自助查询页**：[https://api.qcode.cc/qcode-img/usage](https://api.qcode.cc/qcode-img/usage) — 输入 API Key 查近 30 天用量、详细调用列表、ECharts 趋势图（API Key 仅在浏览器本地存储，不上传）

---

## 计费规则

### 基础定价（每张输出图）

`generations` 和 `edits` 共用同一定价表：

| size | low | medium | high |
|---|---|---|---|
| **1024×1024** | $0.08 (floor) | $0.08 (floor) | $0.211 |
| **1024×1536** | $0.08 (floor) | $0.08 (floor) | $0.165 |
| **1536×1024** | $0.08 (floor) | $0.08 (floor) | $0.165 |
| **2048×2048** | $0.08 (floor) | $0.08 (floor) | $0.285 |

### 最低单次计费 $0.08

- 实际成本 < $0.08 时按 **$0.08** 计费（low / medium 大多触发此 floor）
- 实际成本 ≥ $0.08 时按真实金额计费（不上调）
- **编辑接口（edits）按上游返回的真实 token 用量计费**，不足 $0.08 时按 $0.08 计

### 多张与多输入图

- `n > 1` 时按**输出**张数线性叠加。例：`n=2` + `1024×1024` high = 2 × $0.211 = $0.422
- edits 接口的多输入图（`image=[…N]`）**不按输入张数计费**，按输出张数 `n`
- mask 不影响计费

### 失败不计费

任何 4xx / 5xx 失败请求**不计费**；客户端断开（连接关闭）也不计费。

### 货币

费用以 USD 计算，账户结算遵循 QCode.cc 主账户的货币策略（人民币 / 美元）。

---

## 生成耗时与超时设置

`gpt-image-2` 是基于推理的模型，**生成时间显著长于传统文生图**（如 DALL·E 3 / SDXL）：

| quality | 典型耗时 | 复杂 prompt 极限 |
|---|---|---|
| `low` | 20 – 35 s | ~50 s |
| `medium` | 50 – 90 s | ~120 s |
| `high` | 70 – 120 s | ~150 s |

edits 接口实测（成功编辑请求）：**p50 ≈ 43 s，p95 ≈ 91 s，约 3% 请求超过 100 s**。经 CDN（100 秒硬限）的长请求有小概率遇到 524，建议编辑时使用 `quality=low` / `medium`。

**实践建议**：

- OpenAI Python SDK 默认 timeout 较短，**必须显式设置 `timeout=180.0` 或更高**
- 浏览器 `fetch` 没有默认 timeout，但若用 `AbortController` 设了超时，至少给 180 s
- 中国大陆用户做 medium / high 推荐 `asia.qcode.cc`（直连，无 CDN 100 s 限制）

---

## CDN 100s 硬限（524 错误）

经 `api.qcode.cc / asia.qcode.cc / eu.qcode.cc / us.qcode.cc` 的 HTTPS 请求会经过全球 CDN（CloudFlare）。**CDN 对单个请求等待源响应超过 100 秒会强制返回 `524` 错误**。

| quality | 经 CDN 100s 是否安全 |
|---|---|
| `low` | ✅ 安全（< 35 s）|
| `medium` | ⚠️ 偶发触顶（接近 100 s）|
| `high` | ❌ 经常 524 |

**对策（推荐 medium / high 使用）**：

1. **直接走 `qcode-img` 直连入口** `https://api.qcode.cc/qcode-img/v1`（无 CDN 中转，不受 100 s 限制）
2. 或接受偶发 524 + 客户端自动重试

---

## Prompt 编写要点

### 文生图（generations）

- **支持中英多语言**：可直接写中文 prompt，也可英文，混合也可
- **细节越具体越好**：环境、构图、光线、风格、镜头距离 / 焦段 / 视角等
- **避免品牌名 / 知名人物**：模型可能拒绝或返回模糊结果（OpenAI 内容策略限制）
- **文字渲染**：`gpt-image-2` 文字渲染能力极强，可在图中嵌入英文 / 中文标题、短句、海报文字（写在 prompt 中即可，无需特殊语法）

示例：

```
A vintage poster in Bauhaus style, bold black text "MORNING COFFEE" centered,
warm orange and cream color palette, geometric shapes, slightly textured paper background
```

### 图像编辑（edits）

- **mask 是"哪里要改"，不是"改成什么"**：透明区域 = 要重绘的部分，不透明区域保留原图。prompt 描述目标。mask 像素分辨率需与 `image` 一致（系统会自动缩放）
- **多图融合时 prompt 要明确每张图的角色**：例如 "First image is the scene, second image is the product to be placed in" — gpt-image-2 会按顺序理解多张输入
- **无需传 `input_fidelity`**：gpt-image-2 恒以高保真处理输入图，自动保留原图人物面孔、品牌 logo、文字、商品细节（该参数已废弃，传入会被忽略）
- **不给 mask 时**：整张图按 prompt 重绘（保留原图的语义结构，但所有区域都可能被改）

示例：

```
# 局部修复：把猫加上小皇冠，其他保持原样
prompt = "Put a tiny golden crown on the cat's head. Keep everything else unchanged."
mask = (alpha PNG with only the head area transparent)
```

---

## 与 OpenAI 官方 API 的差异

| 维度 | OpenAI 官方 | QCode.cc |
|---|---|---|
| SDK 兼容性 | — | ✅ 100% 兼容，仅替换 base_url |
| 计费 | 按 token 精算 | 按上述定价表，最低 $0.08 / 张 |
| `/v1/images/generations`（文生图）| ✅ | ✅ |
| `/v1/images/edits`（图像编辑）| ✅ | ✅ **已上线**（2026 年 5 月首发，2026-07-29 恢复并升级：按上游真实 usage 计费）：支持 1-8 张多图融合、mask 局部重绘 |
| `stream + partial_images`（增量返回）| ✅ | ⏳ 暂不支持；**传入 `stream` / `partial_images` 会返回 400** |
| `/v1/images/variations`（纯变体生成）| ✅（老 DALL·E 端点）| ⏳ 暂不支持（可用 `edits` + 空 prompt 替代） |

---

## 在线 Playground

[https://api.qcode.cc/qcode-img/](https://api.qcode.cc/qcode-img/) — 浏览器即可试用：

- **文生图 + 图像编辑** 两个模式都可视化操作（上传图、选 quality、调整 background / output_format 等）
- 输入 API Key + Prompt 立即生成
- 中英双语切换
- 默认 `low` 质量（避免 CDN 524）
- 含完整 API 调用文档（curl / Python / JavaScript 三个 tab + 参数表 + 错误码表）
- 一键下载生成的 PNG / JPEG / WebP

---

## 相关文档

- [接入点与 API 格式](/docs/getting-started/endpoints-and-api-paths) — QCode.cc 全部接入域、协议路径、curl 自测方法
- [计费说明](/docs/reference/billing) — 套餐、配额、费用规则