---
name: nano-banana-gemini-image-pipeline
description: "Google Gemini image API (Nano Banana / Nano Banana Pro) — generate, edit, refine, text-accurate infographics. Production Gemini image generation via the GenAI SDK: call gemini-2.5-flash-image (Nano Banana) and Nano Banana Pro (Gemini 3 Pro Image) with generateContent, handle inline_data image parts, and pass aspect ratio and resolution through image_config. Covers multi-image fusion and conversational editing across turns, legible text and infographic rendering, SynthID watermarking, prompt structuring for photoreal output, and iterative refinement loops in Python and JS."
license: MIT
---

# Nano Banana Image Pipeline

A production wrapper around Google's Gemini image models — `gemini-2.5-flash-image` (Nano Banana) and Nano Banana Pro (Gemini 3 Pro Image) — driven through the `google-genai` SDK. It handles the full loop of generating, editing, fusing, and refining images, including the parts most people get wrong: parsing `inline_data` parts out of the response, setting aspect ratio and resolution correctly, and keeping a conversation alive for iterative edits. Built for developers who want reliable image output from code, not a chat UI.

## When to use it

- Generating product shots, hero images, or social assets from a text prompt at a fixed aspect ratio.
- Producing infographics, posters, or diagrams where the rendered **text must be legible and spelled correctly** — Nano Banana Pro is markedly stronger here than typical diffusion models.
- Editing an existing image conversationally ("now make the sky overcast", "remove the person on the left") without re-uploading each turn.
- Fusing 2+ source images — e.g. dropping a product onto a new background, or blending a style reference with a subject.

## How it works

Calls go through `client.models.generate_content(model=..., contents=[...], config=...)`. Prompts and source images are passed as `contents`; images are sent as `types.Part.from_bytes(data=..., mime_type="image/png")`. Output images come back as candidate parts with `inline_data` — the skill walks `response.candidates[0].content.parts`, picks the parts where `part.inline_data` is set, and writes the bytes out.

Aspect ratio and resolution are passed via `image_config` inside `GenerateContentConfig` (e.g. `aspect_ratio="16:9"`). For multi-turn editing it reuses `client.chats.create(...)` so prior images stay in context.

## Usage

```bash
curl -fsSL --create-dirs -o ~/.claude/skills/nano-banana-gemini-image-pipeline/SKILL.md https://claudeskil.com/skills/nano-banana-gemini-image-pipeline/SKILL.md
export GEMINI_API_KEY=...   # from Google AI Studio
```

```python
from google import genai
from google.genai import types

client = genai.Client()
resp = client.models.generate_content(
    model="gemini-2.5-flash-image",
    contents=["A launch-day infographic: 'Ship Faster', 3 numbered steps"],
    config=types.GenerateContentConfig(
        response_modalities=["IMAGE"],
        image_config=types.ImageConfig(aspect_ratio="4:5"),
    ),
)
for part in resp.candidates[0].content.parts:
    if part.inline_data:
        open("out.png", "wb").write(part.inline_data.data)
```

## Tips & gotchas

- A response can contain **both** a text part and an image part — always filter on `inline_data` rather than assuming `parts[0]` is the image.
- For crisp text and infographics use Nano Banana Pro; `gemini-2.5-flash-image` is cheaper and faster but weaker on dense typography.
- All Gemini-generated images carry an invisible **SynthID** watermark — don't claim outputs are watermark-free.
- If you only ask for `["TEXT"]` modality you'll get no image; set `response_modalities` to include `"IMAGE"`.

## FAQ

**Flash vs. Pro — which?** Use Flash for volume and speed; switch to Pro when text rendering, fine detail, or multi-image fusion fidelity matters.

**Can I keep editing one image?** Yes — use a `chats` session and send follow-up instructions; the prior image stays in context.

**Why is my output blocked or empty?** Check the candidate's `finish_reason` and any safety blocks before reading parts; a filtered response has no image bytes.
