> ## Documentation Index
> Fetch the complete documentation index at: https://docs.laozhang.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Nano Banana Pro APIの画像編集：参照画像14枚と4K

> gemini-3-pro-imageで画像を編集・合成する手順を、LaoZhang APIのキーで実行できるコードとともに説明します。公開URLからの入力と、レスポンスの処理方法も載せています。

Nano Banana Pro（`gemini-3-pro-image`）は、テキストの指示で細部を変えたり、写真のスタイルを変えたり、複数の画像から新しい1枚を作ったりできます。このページではLaoZhang APIの2つのリクエスト形式を扱い、編集はどのサイズでも1回の固定料金です。

| 項目 | 内容 |
| - | - |
| モデルID | `gemini-3-pro-image` |
| エンドポイント | アスペクト比とサイズを指定できるのはGeminiネイティブの `generateContent`。OpenAI互換のchat completionsでも同じ編集ができるが、サイズの設定はない |
| 参照画像 | 1回のリクエストで最大14枚 |
| 画像の入力 | Base64の `inlineData`、または `fileData` での公開URL |
| 出力サイズ | `1K`（既定）、`2K`、`4K` |
| アスペクト比 | 10種。`aspectRatio` で指定 |
| 出力 | レスポンス内のBase64の画像。デコードして保存する |
| マスク | なし。変えたい範囲は言葉で説明する |
| 料金 | どのサイズでも1回\$0.09（2026年9月24日時点の公開価格。[AIモデルのAPI料金一覧](https://docs.laozhang.ai/ja/models.md)を参照） |
| 課金 | HTTP 200の応答は、画像がなくても1回分が課金されます。詳しくは[Nano Bananaの概要](https://docs.laozhang.ai/ja/api-capabilities/nano-banana-image.md)の「課金」 |

テキストだけから画像を作る場合は、[Nano Banana Pro](https://docs.laozhang.ai/ja/api-capabilities/nano-banana-pro-image.md)の画像生成のページを参照してください。

## 始める前に

**1. APIキーを作成する**

[トークン管理](https://api.laozhang.ai/token)でトークン作成のダイアログ（创建令牌）を開き、**課金方式**（计费模式）を**従量優先**（按量优先、推奨）または**回数課金**（按次计费）にして、**作成**（创建）をクリックします。

Nano Banana Proには回数課金の料金しかないため、**従量課金**（按量计费）のキーでは呼び出せません。リクエストが課金される条件は、[Nano Bananaの概要](https://docs.laozhang.ai/ja/api-capabilities/nano-banana-image.md)の「課金」で説明しています。

![LaoZhang APIコンソールのトークン作成ダイアログ。課金方式で回数課金（按次计费）を選んでいる](https://mintcdn.com/laozhangai-edd05f2c/_loZ0Jy0ZI__xJ9z/images/token-create-per-request.png?fit=max\&auto=format\&n=_loZ0Jy0ZI__xJ9z\&q=85\&s=1fdceb804bb3ad50f83a21ec65b4d807)

**2. キーを設定し、依存パッケージをインストールする**

```bash theme={null}
export LAOZHANG_API_KEY="sk-..."  # 自分のLaoZhang APIキーに置き換える
python -m pip install openai requests
```

**3. cURL用の保存関数を追加する**

cURLの例には `jq` が必要です。次のシェル関数は、Geminiネイティブのレスポンスにある最後の画像を、`mimeType` に合った拡張子で保存します。途中経過の画像が一緒に返った場合も、最後の画像が最終結果です。

```bash theme={null}
save_image() {
  local image='[.candidates[]?.content.parts[]? | select(.inlineData and (.thought | not))][-1].inlineData'
  local ext
  case "$(jq -r "$image.mimeType" "$1")" in
    image/png) ext=png ;;
    image/jpeg) ext=jpg ;;
    image/webp) ext=webp ;;
    *) jq '{error, promptFeedback, finishReasons: [.candidates[]?.finishReason]}' "$1"; return 1 ;;
  esac
  jq -r "$image.data" "$1" | base64 --decode > "$2.$ext" && echo "保存しました: $2.$ext"
}
```

レスポンスに画像がないときは、代わりに、エラー、`promptFeedback`、`finishReason` の各フィールドが出力されます。

## ローカルの画像を編集する

リクエストは `POST https://api.laozhang.ai/v1beta/models/gemini-3-pro-image:generateContent` に送ります。`parts` には、最初に指示、そのあとに画像を入れます。ローカルのファイルは、それぞれ `mimeType` をファイルに合わせた `inlineData` パートとして送ります。

> [tab] Python
>
> 次のスクリプトを `nano_banana_pro_edit.py` として保存します。指示と1〜14枚のローカルの画像を送り、レスポンスのすべての画像を保存します。
>
> ```python theme={null}
> """GeminiネイティブのルートでNano Banana Pro（gemini-3-pro-image）を使い、画像を編集または合成する。"""
> import argparse
> import base64
> import os
> import sys
> from pathlib import Path
>
> import requests
>
> URL = "https://api.laozhang.ai/v1beta/models/gemini-3-pro-image:generateContent"
> RATIOS = ["1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"]
> MIME_TYPES = {".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".webp": "image/webp"}
> EXTENSIONS = {"image/png": "png", "image/jpeg": "jpg", "image/webp": "webp"}
>
> parser = argparse.ArgumentParser(description="画像を1枚編集する。または最大14枚の参照画像を合成する。")
> parser.add_argument("prompt", help="編集の指示")
> parser.add_argument("images", nargs="+", help="ローカルのPNG、JPEG、WebPファイル（1〜14枚）")
> parser.add_argument("--ratio", choices=RATIOS, help="出力のアスペクト比。省略すると入力画像に合わせる")
> parser.add_argument("--size", default="1K", choices=["1K", "2K", "4K"])
> parser.add_argument("--out", default="pro-edit", help="拡張子を除いた出力ファイル名")
> args = parser.parse_args()
> if len(args.images) > 14:
>     sys.exit("参照画像は最大14枚までです。")
>
> parts = [{"text": args.prompt}]
> for path in args.images:
>     mime = MIME_TYPES.get(Path(path).suffix.lower())
>     if mime is None:
>         sys.exit(f"PNG、JPEG、WebPのいずれかのファイルを指定してください: {path}")
>     data = base64.b64encode(Path(path).read_bytes()).decode("ascii")
>     parts.append({"inlineData": {"mimeType": mime, "data": data}})
>
> image_config = {"imageSize": args.size}
> if args.ratio:
>     image_config["aspectRatio"] = args.ratio
>
> response = requests.post(
>     URL,
>     headers={"Authorization": f"Bearer {os.environ['LAOZHANG_API_KEY']}"},
>     json={
>         "contents": [{"role": "user", "parts": parts}],
>         "generationConfig": {"responseModalities": ["IMAGE"], "imageConfig": image_config},
>     },
>     timeout=300,
> )
> if response.status_code != 200:
>     sys.exit(f"HTTP {response.status_code}: {response.text[:500]}")
>
> result = response.json()
> images = [
>     part["inlineData"]
>     for candidate in result.get("candidates") or []
>     for part in (candidate.get("content") or {}).get("parts") or []
>     if "inlineData" in part and not part.get("thought")
> ]
> if not images:
>     reasons = [candidate.get("finishReason") for candidate in result.get("candidates") or []]
>     sys.exit(f"画像が返されませんでした: {result.get('promptFeedback') or reasons}")
> for number, image in enumerate(images, start=1):
>     suffix = "" if number == 1 else f"-{number}"
>     output = Path(f"{args.out}{suffix}.{EXTENSIONS.get(image['mimeType'], 'bin')}")
>     output.write_bytes(base64.b64decode(image["data"]))
>     print("保存しました", output)
> ```
>
> 猫の写真に帽子を加え、2Kで出力します。
>
> ```bash theme={null}
> python nano_banana_pro_edit.py "猫に小さな青い魔法使いの帽子をかぶせてください。ポーズ、毛並み、背景はそのままにしてください。" cat.jpg --size 2K --out pro-cat-hat
> ```

> [tab] cURL
>
> 大きな画像でもシェルの引数の上限を超えないよう、ファイルをエンコードして `jq` で本文を組み立てます。`mimeType` はファイルの形式と一致させてください（このJPEGでは `image/jpeg`）。
>
> ```bash theme={null}
> base64 < cat.jpg | tr -d '\n' > cat.b64
> jq -n --rawfile image cat.b64 '{
>   contents: [{
>     role: "user",
>     parts: [
>       {text: "猫に小さな青い魔法使いの帽子をかぶせてください。ポーズ、毛並み、背景はそのままにしてください。"},
>       {inlineData: {mimeType: "image/jpeg", data: $image}}
>     ]
>   }],
>   generationConfig: {
>     responseModalities: ["IMAGE"],
>     imageConfig: {imageSize: "2K"}
>   }
> }' > pro-edit-request.json
>
> curl --fail-with-body --max-time 300 \
>   "https://api.laozhang.ai/v1beta/models/gemini-3-pro-image:generateContent" \
>   -H "Authorization: Bearer $LAOZHANG_API_KEY" \
>   -H "Content-Type: application/json" \
>   --data-binary @pro-edit-request.json \
>   -o pro-edit-response.json
>
> save_image pro-edit-response.json pro-cat-hat
> ```

どちらの例も `aspectRatio` を省略しているため、結果は、入力画像のサイズに合わせるというGoogleの既定どおりになります。形を変えたいときは `aspectRatio`（または `--ratio`）を加えてください。比率とサイズごとのピクセル数は、[Nano Banana Pro](https://docs.laozhang.ai/ja/api-capabilities/nano-banana-pro-image.md)の「出力サイズ」にあります。

4Kの編集は1Kより時間がかかるため、クライアントのタイムアウトには余裕を持たせてください。例では300秒を許容しています。

## 参照画像を合成する

指示の後ろに、プロンプトで参照する順に最大14枚のファイルを並べ、それぞれの画像の役割をプロンプトで示します。

```bash theme={null}
python nano_banana_pro_edit.py "1枚目の画像の人物に2枚目の画像のジャケットを着せ、3枚目の画像の街に立たせてください。人物の顔と髪型はそのままにしてください。" person.jpg jacket.png street.jpg --ratio 3:4 --size 2K --out pro-outfit
```

Googleは14枚の参照画像を用途別に分けています。1回のリクエストでNano Banana Proが受け付ける上限は次のとおりです。

* **オブジェクト画像6枚**：商品や小道具など、結果に忠実に再現したいもの
* **人物画像5枚**：シリーズを通して人物を一貫させるためのもの
* **スタイル画像3枚**：配色や筆づかいなど、見た目を決めるもの

リクエストには画像の役割を指定するフィールドがないため、それぞれの画像をどう使うかは指示の中で説明してください。

## 公開URLの画像を編集する

Geminiネイティブのルートでは、Base64の代わりに `fileData` パートでURLから画像を渡すこともできます。

```bash theme={null}
curl --fail-with-body --max-time 300 \
  "https://api.laozhang.ai/v1beta/models/gemini-3-pro-image:generateContent" \
  -H "Authorization: Bearer $LAOZHANG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contents": [{
      "role": "user",
      "parts": [
        {"text": "窓から差し込む暖かな夕方の光を加えてください。家具と配置はそのままにしてください。"},
        {"fileData": {"fileUri": "https://example.com/images/living-room.png", "mimeType": "image/png"}}
      ]
    }],
    "generationConfig": {
      "responseModalities": ["IMAGE"],
      "imageConfig": {"aspectRatio": "3:2", "imageSize": "2K"}
    }
  }' \
  -o pro-url-edit-response.json

save_image pro-url-edit-response.json pro-living-room
```

`fileUri` は自分の画像の公開HTTPSアドレスに置き換え、`mimeType` もそれに合わせます。画像はリクエストの処理中にそのアドレスから取得されるため、ログイン、Cookie、ボット対策なしで読み込める必要があります。取得できない場合は、ファイルをダウンロードして `inlineData` として送ってください。

* **リクエストが20 MBを超えそうなときはURLを使います。** リクエスト本文全体は20 MB以内に収めてください。`inlineData` で送る画像は合計約15 MB以下にとどめ、それより大きいものは `fileData` で渡すか、先に縮小します。
* サイトの `robots.txt` が画像のパスへのクローラーをブロックしていないことが必要です。署名付きURLは、待ち時間やリトライに備えて少なくとも30分間有効にしてください。
* `fileData` と `inlineData` のパートは、参照する順に同じ `parts` 配列に混在させられます。詳しい条件は、[Nano Bananaの概要](https://docs.laozhang.ai/ja/api-capabilities/nano-banana-image.md)の「大きな画像と画像URL」を参照してください。

## OpenAI互換ルートを使う

すでにOpenAI SDKを使っているアプリでは、chat completionsで編集を送れます。指示と画像を1つのユーザーメッセージに `image_url` パートとして入れます。ローカルのファイルはデータURLとして、公開された画像はHTTPSのURLのまま渡します。

このルートには比率とサイズの設定がありません。2K、4K、固定の比率が必要な場合は、Geminiネイティブのルートを使ってください。画像は、`message.content` の中のBase64のデータURLとして返ります。次のスクリプトを `nano_banana_pro_chat_edit.py` として保存します。

```python theme={null}
"""OpenAI互換ルートで、Nano Banana Proを使って画像を編集または合成する。"""
import argparse
import base64
import os
import re
import sys
from pathlib import Path

from openai import OpenAI

MIME_TYPES = {".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".webp": "image/webp"}
EXTENSIONS = {"png": "png", "jpeg": "jpg", "jpg": "jpg", "webp": "webp"}

parser = argparse.ArgumentParser(description="chat completionsで画像を1枚編集する。または複数枚を合成する。")
parser.add_argument("prompt", help="編集の指示")
parser.add_argument("images", nargs="+", help="ローカルのPNG、JPEG、WebPファイル、または公開されたHTTPSのURL")
parser.add_argument("--out", default="pro-chat-edit", help="拡張子を除いた出力ファイル名")
args = parser.parse_args()

content = [{"type": "text", "text": args.prompt}]
for source in args.images:
    if source.startswith("https://"):
        url = source  # 公開された画像のURLはそのまま送る
    else:
        mime = MIME_TYPES.get(Path(source).suffix.lower())
        if mime is None:
            sys.exit(f"PNG、JPEG、WebPのいずれかのファイルを指定してください: {source}")
        url = f"data:{mime};base64," + base64.b64encode(Path(source).read_bytes()).decode("ascii")
    content.append({"type": "image_url", "image_url": {"url": url}})

# max_retries=0：タイムアウト後の自動リトライで画像が二重に生成・課金されるのを防ぐ
client = OpenAI(api_key=os.environ["LAOZHANG_API_KEY"], base_url="https://api.laozhang.ai/v1", timeout=300, max_retries=0)
reply = client.chat.completions.create(
    model="gemini-3-pro-image",
    messages=[{"role": "user", "content": content}],
)
text = reply.choices[0].message.content or ""

found = re.findall(r"data:image/(png|jpe?g|webp);base64,([A-Za-z0-9+/=]+)", text)
if not found:
    sys.exit(f"画像が返されませんでした: {text[:300]}")
for number, (kind, encoded) in enumerate(found, start=1):
    suffix = "" if number == 1 else f"-{number}"
    output = Path(f"{args.out}{suffix}.{EXTENSIONS[kind]}")
    output.write_bytes(base64.b64decode(encoded + "=" * (-len(encoded) % 4)))
    print("保存しました", output)
```

ある画像の雰囲気を、別の画像に適用します。

```bash theme={null}
python nano_banana_pro_chat_edit.py "1枚目の画像の配色と筆づかいを、2枚目の画像のシーンに適用してください。" style.jpg photo.jpg --out pro-chat-restyle
```

## レスポンスを処理する

* **Geminiネイティブ**：各画像は `candidates[].content.parts[]` の中の `inlineData` パートで、`mimeType` とBase64の `data` を持ちます。
  * `thought: true` が付いたパートは読み飛ばします。Proは描画の前に思考するため、複雑な編集では結果と一緒に途中経過の画像が返ることがあります。最後の画像が最終結果です。
  * ファイルは `mimeType` に合った拡張子で保存します。
* **chat completions**：画像は、`choices[0].message.content` のテキストの中に `data:image/png;base64,...` のようなデータURLとして入っています。接頭辞から形式を読み取って取り除き、長さが4の倍数でなければ `=` のパディングを補ってからデコードします。
* **画像がない**：ネイティブのレスポンスでは各候補の `finishReason` と、あれば `promptFeedback` を、chatのレスポンスでは返答のテキストを確認します。よくある原因は、安全チェックによるブロックか、モデルが指示にテキストだけで答えたことです。

## 編集のプロンプトのコツ

* 顔、商品のラベル、レイアウトなど、変えてはいけない部分を書きます。マスクのパラメーターはないため、変えたい範囲は言葉で説明します。
* 「2枚目の画像のジャケット」のように、各画像を順番と役割で指します。
* 顔やロゴをそのまま残したいときは、それを詳しく描写し、変えてはいけないと明記します。
* 画像内の文字は、正確な文言をかぎかっこで囲み、書体のスタイルを指定します。
* 複雑な編集は段階に分け、保存した結果を次のリクエストの入力にします。

## エラーと課金

Proが受け付ける値を送ってください。

| フィールド | 使える値 | Proでは使えない値 |
| - | - | - |
| `aspectRatio` | 10種の比率のいずれか | `1:4`、`4:1`、`1:8`、`8:1` |
| `imageSize` | `1K`、`2K`、`4K`（Kは大文字） | `512` |

* リクエストがHTTP 200で画像を返さないことがあります。たとえば、安全チェックで出力がブロックされた場合です。
  * 編集は生成と同じく課金されるため、この呼び出しも課金されます。
  * `finishReason`（あれば `promptFeedback` も）を確認し、指示や参照画像を変えてから再送してください。
  * 詳しくは、[Nano Bananaの概要](https://docs.laozhang.ai/ja/api-capabilities/nano-banana-image.md)の「空のレスポンスで課金されないようにする」を参照してください。
* HTTP 401は、キーか `Authorization: Bearer` ヘッダーが間違っていることを示します。Geminiネイティブのルートは、`x-goog-api-key` のキーも受け付けます。
* 429と5xxのレスポンスは、バックオフを入れて再試行します。タイムアウトしたリクエストは、再送する前に呼び出しログを確認してください。
* `fileData` のURLを取得できない場合は、ログインなしで読み込めるか、`robots.txt` が許可しているかを確認するか、画像を `inlineData` として送ってください。
* HTTP 413は、リクエスト本文が大きすぎることを示します。大きな画像はURLで渡すか、リクエスト全体が20 MB以内に収まるよう縮小してください。
* Base64にするとファイルは約3分の1大きくなるため、非常に大きな写真はエンコードの前に縮小してください。

## よくある質問

### /v1/images/editsで編集できる？

できません。Nano Banana Proの編集は、Geminiネイティブの `generateContent` エンドポイントか、OpenAI互換の `/v1/chat/completions` を使います。Images APIの編集エンドポイントは使えません。

### 画像の一部だけを編集できる？

できます。マスクのフィールドはないため、範囲は言葉で指定します。Googleはこれをセマンティックマスキングと呼んでいます。変える要素を名指しし、それ以外はすべてそのままにするよう、たとえば次のように書きます。

> 青いソファだけを茶色の革のソファに変えてください。部屋のほかの部分、レイアウト、照明はそのままにしてください。

ほかのコツは、前述の「編集のプロンプトのコツ」を参照してください。

### aspectRatioを省略すると結果はどんな形？

Googleの既定では出力が入力画像のサイズに合わせられるため、`aspectRatio` を省略すると元の形が保たれます。前述の「ローカルの画像を編集する」の例は、この動作です。形を変えたいときだけ `aspectRatio` を指定し、1K、2K、4Kの選択には `imageSize` を使ってください。

## 関連ページと参考資料

* [Nano Banana Pro](https://docs.laozhang.ai/ja/api-capabilities/nano-banana-pro-image.md) — テキストからの画像生成、比率ごとの出力サイズ、Google検索グラウンディング
* [Nano Banana 2](https://docs.laozhang.ai/ja/api-capabilities/nano-banana2-image.md) — 4Kまでの低コストの生成と編集
* [Nano Bananaの概要](https://docs.laozhang.ai/ja/api-capabilities/nano-banana-image.md) — 5モデル、2つのリクエスト形式、課金ルールの比較
* [Standardの編集](https://docs.laozhang.ai/ja/api-capabilities/nano-banana-image-edit.md) — `gemini-2.5-flash-image` での編集と移行の方法
* [呼び出しログ](https://docs.laozhang.ai/en/faq/call-logs.md) — リクエストのステータスと課金額の確認
* [Google: Nano Banana image generation](https://ai.google.dev/gemini-api/docs/image-generation) — 編集のプロンプト、参照画像の上限、思考
* [Google: generateContent reference](https://ai.google.dev/api/generate-content) — `imageConfig` のフィールド
* [Google: file input methods](https://ai.google.dev/gemini-api/docs/file-input-methods) — インラインデータと公開URLの入力


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.