
Gemini Image Gen
- 4 installs
- 1 repo stars
- Updated November 15, 2025
- aia-11-hn-mib/mib-mockinterviewaibot
gemini-image-gen is a Claude Code skill that generates and edits images from text prompts using Google's Gemini 2.5 Flash Image model.
About
gemini-image-gen is a Claude Code skill for generating and editing images with Google's Gemini 2.5 Flash Image model. A developer uses it to create visuals from text prompts, edit existing images, or compose multiple source images into a new scene. It ships a generate.py helper script and a prompting guide, and supports both Google AI Studio and Vertex AI.
- Generates images from text prompts with Google Gemini 2.5 Flash Image
- Supports image editing, multi-image composition, and iterative refinement
- Includes a generate.py helper with aspect-ratio control and AI Studio or Vertex AI setup
Gemini Image Gen by the numbers
- 4 all-time installs (skills.sh)
- Ranked #1,141 of 1,337 Generative Media skills by installs in the Skillselion catalog
- Data as of Jul 28, 2026 (Skillselion catalog sync)
gemini-image-gen capabilities & compatibility
Requires a Gemini API key; docs list 1290 tokens per generated image.
- Capabilities
- image generation · image editing · image composition
- Works with
- gcp
- Use cases
- image generation
- Pricing
- Bring your own API key
What gemini-image-gen says it does
Generate high-quality images using Google's Gemini 2.5 Flash Image model with text prompts, image editing, and multi-image composition capabilities.
Combine up to 3 source images (recommended):
npx skills add https://github.com/aia-11-hn-mib/mib-mockinterviewaibot --skill gemini-image-genAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 4 |
|---|---|
| repo stars | ★ 1 |
| Last updated | November 15, 2025 |
| Repository | aia-11-hn-mib/mib-mockinterviewaibot ↗ |
What it does
Generate and edit images from text prompts using the Gemini 2.5 Flash Image model.
Who is it for?
Generating images from text, editing existing images, and combining multiple source images into compositions.
Skip if: Long text baked into images, since the docs cap in-image text at 25 characters and 3 phrases.
When should I use this skill?
Generating images from text, editing images, or composing multiple images together.
What you get
Text prompts and source images are turned into generated or edited PNG images.
By the numbers
- 5 supported aspect ratios
- 1290 tokens per image
- up to 3 source images per composition
Files
Gemini Image Generation Skill
Generate high-quality images using Google's Gemini 2.5 Flash Image model with text prompts, image editing, and multi-image composition capabilities.
When to Use This Skill
Use this skill when you need to:
- Generate images from text descriptions
- Edit existing images by adding/removing elements or changing styles
- Combine multiple source images into new compositions
- Iteratively refine images through conversational editing
- Create visual content for documentation, design, or creative projects
Prerequisites
API Key Setup
The skill supports both Google AI Studio and Vertex AI endpoints.
Option 1: Google AI Studio (Default)
The skill automatically detects your GEMINI_API_KEY in this order:
1. Process environment: export GEMINI_API_KEY="your-key" 2. Project root: .env 3. .claude directory: .claude/.env 4. .claude/skills directory: .claude/skills/.env 5. Skill directory: .claude/skills/gemini-image-gen/.env
Get your API key: Visit Google AI Studio
Create .env file with:
GEMINI_API_KEY=your_api_key_hereOption 2: Vertex AI
To use Vertex AI instead:
# Enable Vertex AI
export GEMINI_USE_VERTEX=true
export VERTEX_PROJECT_ID=your-gcp-project-id
export VERTEX_LOCATION=us-central1 # Optional, defaults to us-central1Or in .env file:
GEMINI_USE_VERTEX=true
VERTEX_PROJECT_ID=your-gcp-project-id
VERTEX_LOCATION=us-central1Python Setup
Install required package:
pip install google-genaiQuick Start
Basic Text-to-Image Generation
from google import genai
from google.genai import types
import os
# API key detection handled automatically by helper script
client = genai.Client(api_key=os.getenv('GEMINI_API_KEY'))
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents='A serene mountain landscape at sunset with snow-capped peaks',
config=types.GenerateContentConfig(
response_modalities=['image'],
aspect_ratio='16:9'
)
)
# Save to ./docs/assets/
for i, part in enumerate(response.candidates[0].content.parts):
if part.inline_data:
with open(f'./docs/assets/generated-{i}.png', 'wb') as f:
f.write(part.inline_data.data)Using the Helper Script
For convenience, use the provided helper script that handles API key detection and file saving:
# Generate single image
python .claude/skills/gemini-image-gen/scripts/generate.py \
"A futuristic city with flying cars" \
--aspect-ratio 16:9 \
--output ./docs/assets/city.png
# Generate with specific modalities
python .claude/skills/gemini-image-gen/scripts/generate.py \
"Modern architecture design" \
--response-modalities image text \
--aspect-ratio 1:1Key Features
Aspect Ratios
| Ratio | Resolution | Use Case | Token Cost |
|---|---|---|---|
| 1:1 | 1024×1024 | Social media, avatars | 1290 |
| 16:9 | 1344×768 | Landscapes, banners | 1290 |
| 9:16 | 768×1344 | Mobile, portraits | 1290 |
| 4:3 | 1152×896 | Traditional media | 1290 |
| 3:4 | 896×1152 | Vertical posters | 1290 |
Response Modalities
- `['image']`: Generate only images
- `['text']`: Generate only text descriptions
- `['image', 'text']`: Generate both images and descriptions
Image Editing
Provide existing image + text instructions to modify:
import PIL.Image
img = PIL.Image.open('original.png')
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents=[
'Add a red balloon floating in the sky',
img
]
)Multi-Image Composition
Combine up to 3 source images (recommended):
img1 = PIL.Image.open('background.png')
img2 = PIL.Image.open('foreground.png')
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents=[
'Combine these images into a cohesive scene',
img1,
img2
]
)Prompt Engineering Tips
Structure effective prompts with three elements: 1. Subject: What to generate ("a robot") 2. Context: Environmental setting ("in a futuristic city") 3. Style: Artistic treatment ("cyberpunk style, neon lighting")
Example: "A robot in a futuristic city, cyberpunk style with neon lighting and rain-slicked streets"
Quality modifiers:
- Add terms like "4K", "HDR", "high-quality", "professional photography"
- Specify camera settings: "35mm lens", "shallow depth of field", "golden hour lighting"
Text in images:
- Limit to 25 characters maximum
- Use up to 3 distinct phrases
- Specify font styles: "bold sans-serif title" or "handwritten script"
See references/prompting-guide.md for comprehensive prompt engineering strategies.
Safety Settings
The model includes adjustable safety filters. Configure per-request:
config = types.GenerateContentConfig(
response_modalities=['image'],
safety_settings=[
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
threshold=types.HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE
)
]
)See references/safety-settings.md for detailed configuration options.
Output Management
All generated images should be saved to ./docs/assets/ directory:
# Create directory if needed
mkdir -p ./docs/assetsThe helper script automatically saves to this location with timestamped filenames.
Model Specifications
Model: gemini-2.5-flash-image
- Input tokens: Up to 65,536
- Output tokens: Up to 32,768
- Supported inputs: Text and images
- Supported outputs: Text and images
- Knowledge cutoff: June 2025
- Features: Image generation, structured outputs, batch API, caching
Limitations
- Maximum 3 input images recommended for best results
- Text rendering works best when generated separately first
- Does not support audio/video inputs
- Regional restrictions on child image uploads (EEA, CH, UK)
- Optimal language support: English, Spanish (Mexico), Japanese, Mandarin, Hindi
Error Handling
Common issues and solutions:
API key not found:
# Check environment variables
echo $GEMINI_API_KEY
# Verify .env file exists
cat .claude/skills/gemini-image-gen/.env
# or
cat .envSafety filter blocking:
- Review
response.prompt_feedback.block_reason - Adjust safety settings if appropriate for your use case
- Modify prompt to avoid triggering filters
Token limit exceeded:
- Reduce prompt length
- Use fewer input images
- Simplify image editing instructions
Reference Documentation
For detailed information, see:
references/api-reference.md- Complete API specificationsreferences/prompting-guide.md- Advanced prompt engineeringreferences/safety-settings.md- Safety configuration detailsreferences/code-examples.md- Additional implementation examples
Resources
- Official Documentation
- API Reference
- Get API Key
- Google AI Studio - Interactive testing
# Gemini Image Generation - API Configuration
# Copy this file to .env and configure your API settings
# ==== Google AI Studio (Default) ====
# Get your API key from: https://aistudio.google.com/apikey
GEMINI_API_KEY=your_api_key_here
# ==== Vertex AI (Optional) ====
# Uncomment to use Vertex AI instead of AI Studio
# GEMINI_USE_VERTEX=true
# VERTEX_PROJECT_ID=your-gcp-project-id
# VERTEX_LOCATION=us-central1
Gemini Image Generation Skill
Agent skill for generating high-quality images using Google's Gemini 2.5 Flash Image model.
Overview
This skill enables Claude Code agents to generate images from text prompts, edit existing images, combine multiple images, and iteratively refine results through conversational interaction.
Features
- Text-to-Image: Generate images from descriptive text prompts
- Image Editing: Modify existing images by adding/removing elements or changing styles
- Multi-Image Composition: Combine up to 3 source images into new compositions
- Iterative Refinement: Progressively improve images through multi-turn conversations
- Flexible Aspect Ratios: Support for 1:1, 16:9, 9:16, 4:3, 3:4
- Safety Controls: Configurable content filtering
- SynthID Watermarking: Automatic invisible watermarking on all outputs
Installation
1. Install Python SDK
pip install google-genai2. Get API Key
Visit Google AI Studio to obtain your GEMINI_API_KEY.
3. Configure API Key
The skill checks for the API key in this order:
1. Process environment variable:
export GEMINI_API_KEY="your-key-here"2. Skill directory .env file:
# Create .claude/skills/gemini-image-gen/.env
GEMINI_API_KEY=your-key-here3. Project root .env file:
# Create ./.env in project root
GEMINI_API_KEY=your-key-hereQuick Start
Using the Helper Script
# Generate a simple image
python .claude/skills/gemini-image-gen/scripts/generate.py \
"A serene mountain landscape at sunset"
# Specify aspect ratio
python .claude/skills/gemini-image-gen/scripts/generate.py \
"Modern architecture design" \
--aspect-ratio 16:9
# Generate both image and text
python .claude/skills/gemini-image-gen/scripts/generate.py \
"Futuristic city with flying cars" \
--response-modalities image text
# Custom output path
python .claude/skills/gemini-image-gen/scripts/generate.py \
"Vintage robot illustration" \
--output ./my-images/robot.pngUsing Python Directly
from google import genai
from google.genai import types
import os
client = genai.Client(api_key=os.getenv('GEMINI_API_KEY'))
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents='A peaceful zen garden with raked sand and stones',
config=types.GenerateContentConfig(
response_modalities=['image'],
aspect_ratio='16:9'
)
)
# Save image
for part in response.candidates[0].content.parts:
if part.inline_data:
with open('./docs/assets/zen-garden.png', 'wb') as f:
f.write(part.inline_data.data)Directory Structure
gemini-image-gen/
├── SKILL.md # Main skill entry point
├── README.md # This file
├── scripts/
│ └── generate.py # Helper script with API key detection
└── references/
├── api-reference.md # Complete API documentation
├── prompting-guide.md # Prompt engineering strategies
├── safety-settings.md # Safety configuration guide
└── code-examples.md # Implementation examplesDocumentation
Main Documentation
- [SKILL.md](./SKILL.md) - Main skill instructions with quick start guide
- [README.md](./README.md) - This overview document
Reference Documentation
- [api-reference.md](./references/api-reference.md) - Complete API specifications, parameters, error handling
- [prompting-guide.md](./references/prompting-guide.md) - Advanced prompt engineering techniques
- [safety-settings.md](./references/safety-settings.md) - Content filtering and safety configuration
- [code-examples.md](./references/code-examples.md) - Practical implementation examples
Model Information
Model: gemini-2.5-flash-image
- Latest Update: October 2025
- Knowledge Cutoff: June 2025
- Input Tokens: 65,536
- Output Tokens: 32,768
- Supported Inputs: Text and images
- Supported Outputs: Text and images
Capabilities
✅ Image generation ✅ Structured outputs ✅ Batch API ✅ Caching
❌ Audio generation ❌ Code execution ❌ Function calling ❌ Live API
Output Management
All generated images are automatically saved to:
./docs/assets/The directory is created automatically if it doesn't exist. Images are saved with timestamped filenames unless a custom path is specified.
Common Use Cases
Product Photography
generate("Commercial product photo of wireless headphones, studio lighting, white background, professional photography")Social Media Assets
# Square for Instagram
generate("Modern minimalist quote design", aspect_ratio='1:1')
# Story format
generate("Behind-the-scenes photo", aspect_ratio='9:16')Marketing Materials
# Banner
generate("Website hero banner for tech startup", aspect_ratio='16:9')
# Poster
generate("Event poster design", aspect_ratio='3:4')Image Editing
import PIL.Image
original = PIL.Image.open('photo.jpg')
edit_image("Add golden hour lighting effect", original)Troubleshooting
API Key Not Found
# Verify environment variable
echo $GEMINI_API_KEY
# Check .env files
cat .claude/skills/gemini-image-gen/.env
cat .envSafety Filter Blocking
If content is blocked: 1. Review the safety ratings in the response 2. Adjust your prompt to be more specific 3. Consider adjusting safety settings if appropriate 4. See references/safety-settings.md for configuration options
Image Quality Issues
For better results: 1. Add quality modifiers: "4K", "professional", "high detail" 2. Specify technical details: "35mm lens", "soft lighting" 3. Include style references: "impressionist style", "photorealistic" 4. See references/prompting-guide.md for advanced techniques
Limitations
- Maximum 3 input images recommended for multi-image composition
- Text rendering limited to 25 characters per element
- Optimal language support: English, Spanish, Japanese, Mandarin, Hindi
- Regional restrictions on child images (EEA, CH, UK)
- No audio/video input support
Resources
- Official Documentation
- Get API Key
- Google AI Studio - Interactive testing
- API Reference
- Pricing Information
License
MIT License - See LICENSE file for details
Support
For issues or questions: 1. Check the reference documentation in ./references/ 2. Review official documentation 3. Test in Google AI Studio 4. Report bugs or request features in the project repository
Version
1.0.0 - Initial release with Gemini 2.5 Flash Image support
Gemini Image Generation API Reference
Complete technical reference for the Gemini 2.5 Flash Image model API.
Model Information
Model Name: gemini-2.5-flash-image
Version: Latest update October 2025 Knowledge Cutoff: June 2025
Capabilities
| Feature | Support |
|---|---|
| Image generation | ✓ |
| Structured outputs | ✓ |
| Batch API | ✓ |
| Caching | ✓ |
| Audio generation | ✗ |
| Code execution | ✗ |
| Function calling | ✗ |
| Thinking mode | ✗ |
| Live API | ✗ |
| Search grounding | ✗ |
Token Limits
- Input tokens: 65,536
- Output tokens: 32,768
- Approximate conversion: ~4 characters per token, 100 tokens ≈ 60-80 words
API Endpoint
POST https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-image:generateContent
Authentication
Include API key as header:
-H "x-goog-api-key: $GEMINI_API_KEY"Or as query parameter:
?key=$GEMINI_API_KEYRequest Structure
Python SDK
from google import genai
from google.genai import types
client = genai.Client(api_key="your-api-key")
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents='Your prompt here',
config=types.GenerateContentConfig(
response_modalities=['image'],
aspect_ratio='16:9',
safety_settings=[
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
threshold=types.HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE
)
]
)
)REST API
curl -X POST \
"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-image:generateContent" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [{
"parts": [{
"text": "Your prompt here"
}]
}],
"generationConfig": {
"response_modalities": ["IMAGE"],
"aspect_ratio": "16:9"
}
}'Configuration Parameters
GenerateContentConfig
response_modalities (List[str])
['image']- Generate only images['text']- Generate only text['image', 'text']- Generate both images and text descriptions
aspect_ratio (str)
'1:1'- Square (1024×1024) - Default'16:9'- Landscape (1344×768)'9:16'- Portrait (768×1344)'4:3'- Traditional landscape (1152×896)'3:4'- Traditional portrait (896×1152)
safety_settings (List[SafetySetting])
- Configure content filtering (see safety-settings.md)
system_instruction (str, optional)
- Developer-defined system instructions
- Currently text-only
cached_content (str, optional)
- Reference to previously cached content
Token Costs by Aspect Ratio
All aspect ratios cost the same:
| Aspect Ratio | Resolution | Input Tokens |
|---|---|---|
| 1:1 | 1024×1024 | 1290 |
| 16:9 | 1344×768 | 1290 |
| 9:16 | 768×1344 | 1290 |
| 4:3 | 1152×896 | 1290 |
| 3:4 | 896×1152 | 1290 |
Content Input Formats
Text-Only Prompts
contents='A serene mountain landscape at sunset'Text with Images
import PIL.Image
img = PIL.Image.open('input.png')
contents=[
'Add a red balloon to this image',
img
]Multiple Images
img1 = PIL.Image.open('image1.png')
img2 = PIL.Image.open('image2.png')
contents=[
'Combine these images into a cohesive scene',
img1,
img2
]Note: Maximum 3 input images recommended for optimal results.
Image Input Formats
Supported formats:
- JPEG (.jpg, .jpeg)
- PNG (.png)
- GIF (.gif)
- WebP (.webp)
Input methods: 1. PIL.Image objects (Python SDK) 2. Base64-encoded data with MIME type 3. File URI after uploading via Files API
Response Structure
GenerateContentResponse
response = client.models.generate_content(...)
# Access response
for candidate in response.candidates:
for part in candidate.content.parts:
# Image data
if hasattr(part, 'inline_data') and part.inline_data:
image_bytes = part.inline_data.data
mime_type = part.inline_data.mime_type
# Text data
if hasattr(part, 'text'):
text = part.text
# Check finish reason
finish_reason = response.candidates[0].finish_reason
# Values: FINISH_REASON_UNSPECIFIED, STOP, MAX_TOKENS, SAFETY, RECITATION, OTHER
# Safety feedback
if response.prompt_feedback:
block_reason = response.prompt_feedback.block_reason
safety_ratings = response.prompt_feedback.safety_ratings
# Usage metadata
usage = response.usage_metadata
print(f"Input tokens: {usage.prompt_token_count}")
print(f"Output tokens: {usage.candidates_token_count}")
print(f"Total tokens: {usage.total_token_count}")Finish Reasons
| Reason | Description |
|---|---|
| STOP | Natural completion |
| MAX_TOKENS | Reached token limit |
| SAFETY | Safety filter triggered |
| RECITATION | Content repetition detected |
| OTHER | Other reason |
| FINISH_REASON_UNSPECIFIED | Unknown reason |
Error Handling
Common Errors
API Key Not Found
Error: API key not validSolution: Verify API key is set correctly
Invalid Aspect Ratio
Error: Invalid aspect_ratio valueSolution: Use one of: 1:1, 16:9, 9:16, 4:3, 3:4
Token Limit Exceeded
Error: Request exceeds maximum token limitSolution: Reduce prompt length or simplify request
Safety Filter Blocking
finish_reason: SAFETYSolution: Check safety_ratings and adjust prompt or safety settings
Error Response Example
try:
response = client.models.generate_content(...)
except Exception as e:
print(f"Error: {e}")
# Handle error appropriatelyRate Limits
Refer to Google AI pricing documentation for current rate limits and quotas.
Best practices:
- Implement exponential backoff for retries
- Cache responses when appropriate
- Use batch API for multiple requests
Streaming Alternative
Use streaming for real-time response generation:
response_stream = client.models.generate_content_stream(
model='gemini-2.5-flash-image',
contents='Your prompt',
config=config
)
for chunk in response_stream:
# Process each chunk as it arrives
for part in chunk.candidates[0].content.parts:
if hasattr(part, 'text'):
print(part.text, end='')Note: Streaming is more useful for text generation; images are typically received complete.
Additional Features
Caching
Cache frequently used content to reduce costs:
# Create cached content
cached = client.caches.create(
model='gemini-2.5-flash-image',
contents='Reusable context or instructions'
)
# Use cached content
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents='New prompt',
config=types.GenerateContentConfig(
cached_content=cached.name
)
)Batch API
Process multiple requests efficiently:
# Submit batch job
batch_job = client.batches.create(
model='gemini-2.5-flash-image',
requests=[
{'contents': 'Prompt 1'},
{'contents': 'Prompt 2'},
{'contents': 'Prompt 3'}
]
)
# Check status
status = client.batches.get(batch_job.name)
# Get results when complete
if status.state == 'SUCCEEDED':
results = client.batches.get_results(batch_job.name)SynthID Watermarking
All generated images include SynthID watermarking automatically. This is:
- Invisible to human perception
- Robust to common modifications
- Detectable via SynthID verification tools
No configuration required - watermarking is always applied.
Language Support
Optimal performance in:
- English (primary)
- Spanish (Mexico)
- Japanese
- Mandarin (Simplified)
- Hindi
Other languages may work but with reduced quality.
Regional Restrictions
Child image uploads are restricted in:
- European Economic Area (EEA)
- Switzerland (CH)
- United Kingdom (UK)
The API will reject requests containing images of children from these regions.
Resources
Gemini Image Generation Code Examples
Practical implementation examples for common use cases.
Basic Examples
Simple Text-to-Image
from google import genai
from google.genai import types
import os
# Initialize client
client = genai.Client(api_key=os.getenv('GEMINI_API_KEY'))
# Generate image
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents='A serene mountain landscape at sunset',
config=types.GenerateContentConfig(
response_modalities=['image'],
aspect_ratio='16:9'
)
)
# Save image
for i, part in enumerate(response.candidates[0].content.parts):
if part.inline_data:
with open(f'output-{i}.png', 'wb') as f:
f.write(part.inline_data.data)
print(f"Saved: output-{i}.png")Generate with Text Description
# Generate both image and descriptive text
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents='A futuristic city with flying cars',
config=types.GenerateContentConfig(
response_modalities=['image', 'text'],
aspect_ratio='16:9'
)
)
# Process response
for part in response.candidates[0].content.parts:
# Save images
if hasattr(part, 'inline_data') and part.inline_data:
with open('city.png', 'wb') as f:
f.write(part.inline_data.data)
# Print text
if hasattr(part, 'text'):
print(f"Description: {part.text}")Image Editing
Add Elements to Existing Image
import PIL.Image
# Load existing image
original = PIL.Image.open('photo.jpg')
# Add element
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents=[
'Add a red balloon floating in the sky',
original
],
config=types.GenerateContentConfig(
response_modalities=['image']
)
)
# Save edited image
for part in response.candidates[0].content.parts:
if part.inline_data:
with open('photo-with-balloon.png', 'wb') as f:
f.write(part.inline_data.data)Remove Elements
original = PIL.Image.open('scene.jpg')
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents=[
'Remove the car from this image, keep everything else',
original
]
)
# Save result
for part in response.candidates[0].content.parts:
if part.inline_data:
with open('scene-no-car.png', 'wb') as f:
f.write(part.inline_data.data)Style Transfer
photo = PIL.Image.open('portrait.jpg')
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents=[
'Transform this photo into an oil painting style, impressionist aesthetic',
photo
]
)
# Save stylized version
for part in response.candidates[0].content.parts:
if part.inline_data:
with open('portrait-oil-painting.png', 'wb') as f:
f.write(part.inline_data.data)Multi-Image Composition
Combine Two Images
background = PIL.Image.open('landscape.jpg')
foreground = PIL.Image.open('subject.jpg')
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents=[
'Place the subject from the second image into the landscape from the first image, maintaining consistent lighting',
background,
foreground
]
)
# Save composition
for part in response.candidates[0].content.parts:
if part.inline_data:
with open('composite.png', 'wb') as f:
f.write(part.inline_data.data)Create Collage
img1 = PIL.Image.open('photo1.jpg')
img2 = PIL.Image.open('photo2.jpg')
img3 = PIL.Image.open('photo3.jpg')
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents=[
'Create a horizontal collage layout with these three images arranged side by side with thin white borders',
img1, img2, img3
],
config=types.GenerateContentConfig(
aspect_ratio='16:9'
)
)
# Save collage
for part in response.candidates[0].content.parts:
if part.inline_data:
with open('collage.png', 'wb') as f:
f.write(part.inline_data.data)Batch Processing
Generate Multiple Variations
def generate_variations(prompt, count=4, aspect_ratio='1:1'):
"""Generate multiple variations of the same prompt"""
variations = []
for i in range(count):
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents=prompt,
config=types.GenerateContentConfig(
response_modalities=['image'],
aspect_ratio=aspect_ratio
)
)
# Save each variation
for part in response.candidates[0].content.parts:
if part.inline_data:
filename = f'variation-{i}.png'
with open(filename, 'wb') as f:
f.write(part.inline_data.data)
variations.append(filename)
print(f"Generated: {filename}")
return variations
# Usage
variations = generate_variations(
"Modern minimalist logo design",
count=4,
aspect_ratio='1:1'
)Batch Processing with Different Prompts
def batch_generate(prompts, output_dir='./output'):
"""Generate images for multiple prompts"""
import os
os.makedirs(output_dir, exist_ok=True)
results = []
for idx, prompt in enumerate(prompts):
print(f"Processing {idx + 1}/{len(prompts)}: {prompt}")
try:
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents=prompt,
config=types.GenerateContentConfig(
response_modalities=['image']
)
)
# Save image
for part in response.candidates[0].content.parts:
if part.inline_data:
filename = f'{output_dir}/image-{idx:03d}.png'
with open(filename, 'wb') as f:
f.write(part.inline_data.data)
results.append({
'prompt': prompt,
'filename': filename,
'success': True
})
except Exception as e:
print(f"Error: {e}")
results.append({
'prompt': prompt,
'filename': None,
'success': False,
'error': str(e)
})
return results
# Usage
prompts = [
"A serene mountain landscape",
"Modern architecture design",
"Abstract geometric art",
"Vintage car illustration"
]
results = batch_generate(prompts)
# Print summary
for r in results:
status = "✓" if r['success'] else "✗"
print(f"{status} {r['prompt']}: {r.get('filename', r.get('error'))}")Error Handling
Comprehensive Error Handler
def safe_generate(prompt, max_retries=3, **config_kwargs):
"""Generate image with error handling and retries"""
for attempt in range(max_retries):
try:
config = types.GenerateContentConfig(
response_modalities=['image'],
**config_kwargs
)
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents=prompt,
config=config
)
# Check if blocked by safety
if response.candidates[0].finish_reason == 'SAFETY':
print("Content blocked by safety filters")
return None
# Extract image
for part in response.candidates[0].content.parts:
if part.inline_data:
return part.inline_data.data
print("No image in response")
return None
except Exception as e:
print(f"Attempt {attempt + 1} failed: {e}")
if attempt < max_retries - 1:
print("Retrying...")
continue
else:
print("Max retries reached")
raise
return None
# Usage
image_data = safe_generate(
"A peaceful garden scene",
aspect_ratio='16:9'
)
if image_data:
with open('garden.png', 'wb') as f:
f.write(image_data)Handle Safety Blocks
def generate_with_safety_check(prompt):
"""Generate image with detailed safety feedback"""
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents=prompt,
config=types.GenerateContentConfig(
response_modalities=['image']
)
)
# Check prompt feedback
if response.prompt_feedback and response.prompt_feedback.block_reason:
print("❌ Prompt blocked")
print(f"Reason: {response.prompt_feedback.block_reason}")
for rating in response.prompt_feedback.safety_ratings:
print(f" {rating.category}: {rating.probability}")
return None
# Check response
candidate = response.candidates[0]
if candidate.finish_reason == 'SAFETY':
print("❌ Response blocked")
for rating in candidate.safety_ratings:
if rating.blocked:
print(f" {rating.category}: {rating.probability} (BLOCKED)")
return None
# Extract image
for part in candidate.content.parts:
if part.inline_data:
return part.inline_data.data
return None
# Usage
image_data = generate_with_safety_check("Your prompt")
if image_data:
with open('output.png', 'wb') as f:
f.write(image_data)
else:
print("Generation failed or was blocked")Advanced Patterns
Iterative Refinement
class ImageIterator:
"""Iteratively refine an image through conversation"""
def __init__(self, client, initial_prompt):
self.client = client
self.history = []
self.current_image = None
# Generate initial image
self.refine(initial_prompt)
def refine(self, instruction):
"""Apply refinement instruction"""
# Build contents
if self.current_image:
contents = [instruction, self.current_image]
else:
contents = instruction
# Generate
response = self.client.models.generate_content(
model='gemini-2.5-flash-image',
contents=contents
)
# Extract image
for part in response.candidates[0].content.parts:
if part.inline_data:
# Convert bytes to PIL Image for next iteration
from io import BytesIO
self.current_image = PIL.Image.open(
BytesIO(part.inline_data.data)
)
# Track history
self.history.append(instruction)
return self.current_image
def save(self, filename):
"""Save current image"""
if self.current_image:
self.current_image.save(filename)
# Usage
iterator = ImageIterator(client, "A cozy coffee shop interior")
iterator.refine("Add warm lighting from Edison bulbs")
iterator.refine("Add a person reading by the window")
iterator.refine("Make the colors more vibrant")
iterator.save("final-coffee-shop.png")Automated Asset Generation
def generate_asset_set(base_prompt, aspects, output_dir='./assets'):
"""Generate a complete asset set with multiple aspect ratios"""
import os
os.makedirs(output_dir, exist_ok=True)
asset_map = {
'square': '1:1', # Social media
'landscape': '16:9', # Banners
'portrait': '9:16', # Stories
'classic': '4:3' # Presentations
}
results = {}
for name, ratio in asset_map.items():
print(f"Generating {name} ({ratio})...")
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents=base_prompt,
config=types.GenerateContentConfig(
response_modalities=['image'],
aspect_ratio=ratio
)
)
# Save
for part in response.candidates[0].content.parts:
if part.inline_data:
filename = f'{output_dir}/{name}.png'
with open(filename, 'wb') as f:
f.write(part.inline_data.data)
results[name] = {
'filename': filename,
'aspect_ratio': ratio
}
print(f" Saved: {filename}")
return results
# Usage
assets = generate_asset_set(
"Modern tech startup branding illustration, minimalist style, blue and purple colors"
)
# Results include: square, landscape, portrait, classic variantsA/B Testing Generator
def generate_ab_variants(prompt, variations, aspect_ratio='1:1'):
"""Generate A/B test variants with slight modifications"""
results = []
for i, variation in enumerate(variations):
full_prompt = f"{prompt}, {variation}"
print(f"Generating variant {i + 1}: {variation}")
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents=full_prompt,
config=types.GenerateContentConfig(
response_modalities=['image', 'text'],
aspect_ratio=aspect_ratio
)
)
# Extract results
variant_data = {
'variation': variation,
'image': None,
'description': None
}
for part in response.candidates[0].content.parts:
if hasattr(part, 'inline_data') and part.inline_data:
filename = f'variant-{chr(65 + i)}.png' # A, B, C, etc.
with open(filename, 'wb') as f:
f.write(part.inline_data.data)
variant_data['image'] = filename
if hasattr(part, 'text'):
variant_data['description'] = part.text
results.append(variant_data)
return results
# Usage
base = "Product hero image for modern headphones"
variants = [
"minimalist white background",
"dramatic black background with spotlight",
"lifestyle setting with person wearing headphones"
]
ab_results = generate_ab_variants(base, variants, aspect_ratio='16:9')
# Print summary
for i, result in enumerate(ab_results):
print(f"\nVariant {chr(65 + i)}: {result['variation']}")
print(f" Image: {result['image']}")
print(f" Description: {result['description']}")Integration Examples
Flask API Endpoint
from flask import Flask, request, send_file, jsonify
from io import BytesIO
import os
app = Flask(__name__)
client = genai.Client(api_key=os.getenv('GEMINI_API_KEY'))
@app.route('/generate', methods=['POST'])
def generate_image():
"""API endpoint for image generation"""
data = request.json
prompt = data.get('prompt')
aspect_ratio = data.get('aspect_ratio', '1:1')
if not prompt:
return jsonify({'error': 'Missing prompt'}), 400
try:
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents=prompt,
config=types.GenerateContentConfig(
response_modalities=['image'],
aspect_ratio=aspect_ratio
)
)
# Extract image
for part in response.candidates[0].content.parts:
if part.inline_data:
return send_file(
BytesIO(part.inline_data.data),
mimetype='image/png',
as_attachment=True,
download_name='generated.png'
)
return jsonify({'error': 'No image generated'}), 500
except Exception as e:
return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
app.run(debug=True)CLI Tool
#!/usr/bin/env python3
import click
from google import genai
import os
@click.command()
@click.argument('prompt')
@click.option('--aspect-ratio', '-a', default='1:1', help='Aspect ratio')
@click.option('--output', '-o', default='output.png', help='Output file')
def cli_generate(prompt, aspect_ratio, output):
"""CLI tool for image generation"""
client = genai.Client(api_key=os.getenv('GEMINI_API_KEY'))
click.echo(f"Generating: {prompt}")
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents=prompt,
config=types.GenerateContentConfig(
response_modalities=['image'],
aspect_ratio=aspect_ratio
)
)
# Save image
for part in response.candidates[0].content.parts:
if part.inline_data:
with open(output, 'wb') as f:
f.write(part.inline_data.data)
click.echo(f"Saved: {output}")
return
click.echo("No image generated", err=True)
if __name__ == '__main__':
cli_generate()Performance Optimization
Concurrent Generation
import asyncio
from concurrent.futures import ThreadPoolExecutor
def generate_single(prompt, index):
"""Generate single image (thread-safe)"""
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents=prompt
)
for part in response.candidates[0].content.parts:
if part.inline_data:
filename = f'output-{index}.png'
with open(filename, 'wb') as f:
f.write(part.inline_data.data)
return filename
return None
def generate_concurrent(prompts, max_workers=4):
"""Generate multiple images concurrently"""
with ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = [
executor.submit(generate_single, prompt, i)
for i, prompt in enumerate(prompts)
]
results = [future.result() for future in futures]
return results
# Usage
prompts = [
"Mountain landscape",
"Ocean sunset",
"Forest path",
"Desert dunes"
]
results = generate_concurrent(prompts, max_workers=4)
print(f"Generated {len([r for r in results if r])} images")Resources
- See
api-reference.mdfor complete API documentation - See
prompting-guide.mdfor prompt engineering strategies - See
safety-settings.mdfor content filtering configuration
Gemini Image Generation Prompting Guide
Comprehensive guide to crafting effective prompts for high-quality image generation.
Prompt Structure
Effective prompts combine three core elements:
1. Subject - What to generate 2. Context - Environmental setting and background 3. Style - Artistic treatment and visual approach
Example Structure
Subject: A vintage robot
Context: Standing in a 1950s diner
Style: Retro-futuristic art style with warm lighting and chrome detailsCombined: "A vintage robot standing in a 1950s diner, retro-futuristic art style with warm lighting and chrome details"
Basic Prompting Principles
Be Clear and Specific
❌ Vague: "A nice landscape" ✓ Specific: "A serene mountain landscape at golden hour with snow-capped peaks reflected in a crystal-clear alpine lake"
Use Descriptive Details
Include sensory and visual details:
- Colors: "deep crimson sunset", "emerald green foliage"
- Lighting: "soft diffused light", "dramatic shadows", "neon glow"
- Textures: "weathered wood", "smooth glass", "rough stone"
- Mood: "peaceful atmosphere", "energetic vibe", "mysterious ambiance"
Specify Composition
Guide the visual arrangement:
- "Centered composition"
- "Rule of thirds"
- "Close-up shot"
- "Wide-angle view"
- "Aerial perspective"
- "Low angle looking up"
Quality Modifiers
Add these terms to improve output quality:
General Quality
- "high quality"
- "professional"
- "detailed"
- "4K resolution"
- "HDR"
- "sharp focus"
- "crisp details"
Technical Specifications
- "8K ultra HD"
- "photorealistic"
- "studio quality"
- "award-winning"
- "masterpiece"
Professional Context
- "by a professional photographer"
- "commercial photography"
- "editorial quality"
- "gallery-worthy"
Photography Prompting
Camera Settings
Focal Length:
- "35mm lens" - Standard perspective
- "50mm lens" - Natural perspective
- "85mm lens" - Portrait lens
- "24mm wide-angle" - Expansive view
- "200mm telephoto" - Compressed perspective
- "Fisheye lens" - Ultra wide, distorted
Aperture Effects:
- "shallow depth of field" - Blurred background
- "f/1.8 aperture" - Very blurred background
- "deep focus" - Everything sharp
- "bokeh effect" - Aesthetic blur
Shutter Speed:
- "fast shutter speed" - Frozen motion
- "motion blur" - Movement trails
- "long exposure" - Smooth water/light trails
ISO & Film:
- "low ISO, clean image"
- "film grain"
- "pushed film aesthetic"
Lighting Conditions
Natural Light:
- "golden hour lighting" - Warm, soft
- "blue hour" - Cool twilight
- "harsh midday sun" - Strong shadows
- "overcast soft light" - Even, diffused
- "backlit" - Subject in shadow, bright background
- "rim lighting" - Edge highlights
Artificial Light:
- "studio lighting"
- "three-point lighting"
- "dramatic side lighting"
- "neon lights"
- "candlelight"
- "fluorescent lighting"
Quality:
- "soft diffused light"
- "hard light with sharp shadows"
- "volumetric lighting" - Light rays visible
- "ambient lighting"
- "cinematic lighting"
Camera Positions
Angle:
- "eye level"
- "bird's eye view" / "aerial view"
- "worm's eye view" / "from below"
- "Dutch angle" - Tilted
- "over-the-shoulder"
Distance:
- "extreme close-up"
- "close-up"
- "medium shot"
- "full shot"
- "long shot"
- "extreme long shot"
Film Types & Aesthetics
- "35mm film"
- "medium format film"
- "Polaroid"
- "black and white film"
- "Kodachrome"
- "Fujifilm Velvia" - Saturated colors
- "Ilford HP5" - B&W with grain
Artistic Styles
Art Movements
- "impressionist" - Soft, painterly
- "expressionist" - Emotional, distorted
- "surrealist" - Dreamlike, bizarre
- "cubist" - Geometric, fragmented
- "art deco" - Geometric, elegant
- "art nouveau" - Organic, decorative
- "pop art" - Bold, graphic
- "minimalist" - Simple, clean
- "baroque" - Ornate, dramatic
- "renaissance" - Classical, realistic
Contemporary Styles
- "cyberpunk" - Neon, futuristic
- "steampunk" - Victorian, mechanical
- "vaporwave" - Retro digital aesthetic
- "synthwave" - 80s neon aesthetic
- "brutalist" - Raw concrete, geometric
Illustration Types
- "watercolor painting"
- "oil painting"
- "acrylic painting"
- "digital painting"
- "pencil sketch"
- "ink drawing"
- "charcoal drawing"
- "vector art"
- "isometric illustration"
- "flat design"
- "3D render"
Advanced Techniques
Shapes and Materials
Describe objects in terms of unconventional properties:
"A coffee cup made of glass"
"A building in the shape of a wave"
"Furniture made of clouds"
"Architecture constructed from paper"Mood and Atmosphere
Set emotional tone:
"peaceful and serene atmosphere"
"tense and dramatic mood"
"whimsical and playful feel"
"melancholic and nostalgic ambiance"
"energetic and vibrant vibe"Time of Day
Specify temporal context:
- "dawn" - Early morning light
- "morning" - Bright, fresh
- "midday" - Overhead sun
- "afternoon" - Warm light
- "dusk" - Fading light
- "twilight" - Blue/purple tones
- "night" - Darkness, artificial light
- "midnight" - Deep darkness
Weather Conditions
Include environmental effects:
- "clear sunny day"
- "overcast clouds"
- "rain falling"
- "heavy fog"
- "snow falling"
- "storm clouds"
- "misty morning"
Text in Images
Best Practices
Length Limits:
- Maximum 25 characters per text element
- Use up to 3 distinct phrases
- Keep it short and simple
Examples: ✓ "OPEN" ✓ "SALE TODAY" ✓ "Welcome Home" ❌ "Welcome to our beautiful establishment where we serve delicious food"
Font Specifications
Include font details in prompt:
"Bold sans-serif text saying 'SALE'"
"Handwritten script text saying 'Welcome'"
"Retro 1950s style typography displaying 'Diner'"
"Modern minimalist text reading 'STUDIO'"Size Indicators
- "small text label"
- "medium-sized title"
- "large bold headline"
- "tiny footnote text"
Positioning
- "text centered at top"
- "text in bottom left corner"
- "text floating in center"
- "text along the edge"
Note: Text generation may require multiple attempts. Regenerate until satisfied with results.
Multi-Image Composition
When combining multiple input images:
Clarity in Intent
Be specific about how images should combine:
"Combine these images: place the subject from image 1 in the environment from image 2"
"Merge these photos into a cohesive landscape scene"
"Create a collage layout with these three images arranged horizontally"Style Consistency
Specify unified visual treatment:
"Combine these images with consistent lighting and color palette"
"Blend these photos seamlessly into a single cohesive scene"Recommended Limits
- Maximum: 3 input images for best results
- Fewer images generally produce higher quality
- More images increase complexity and potential inconsistencies
Image Editing
When modifying existing images:
Addition Instructions
"Add a red balloon floating in the sky"
"Add rain falling in this scene"
"Add a person walking in the background"Removal Instructions
"Remove the car from this image"
"Remove all text from the image"
"Remove the background, keep only the subject"Modification Instructions
"Change the time of day to sunset"
"Change the color scheme to black and white"
"Change the style to watercolor painting"
"Make the image more vibrant and saturated"Style Transfer
"Apply impressionist painting style to this image"
"Convert this photo to look like a comic book illustration"
"Transform this image into cyberpunk aesthetic"Aspect Ratio Selection
Choose based on use case:
| Ratio | Best For | Example Use Cases |
|---|---|---|
| 1:1 | Social media posts, avatars, thumbnails | Instagram posts, profile pictures |
| 16:9 | Landscapes, banners, presentations | YouTube thumbnails, website headers |
| 9:16 | Portraits, mobile content, stories | Instagram stories, TikTok videos |
| 4:3 | Traditional media, presentations | PowerPoint slides, classic photography |
| 3:4 | Vertical posters, magazine covers | Pinterest pins, poster designs |
Iterative Refinement
Multi-Turn Conversations
Build on previous generations:
Turn 1: "A cozy coffee shop interior" Turn 2: "Add warm lighting from hanging Edison bulbs" Turn 3: "Add a person reading by the window" Turn 4: "Make the scene more vibrant and inviting"
Progressive Enhancement
Start broad, then add specifics:
1. "A mountain landscape" 2. "A snow-capped mountain landscape at sunset" 3. "A dramatic snow-capped mountain landscape at golden hour with reflecting alpine lake in foreground" 4. "...professional landscape photography, 35mm lens, deep focus"
Common Patterns
Portrait Photography
"Professional portrait of [subject], natural lighting, shallow depth of field, 85mm lens, soft focus background, warm tones"Product Photography
"Commercial product photo of [product], studio lighting, white background, sharp focus, high resolution, professional photography"Architectural Photography
"Architectural photography of [building], wide-angle lens, dramatic perspective, blue hour lighting, HDR, professional quality"Food Photography
"Food photography of [dish], overhead shot, natural lighting, shallow depth of field, rustic background, appetizing presentation"Landscape Photography
"Landscape photography of [location], golden hour, wide-angle lens, dramatic clouds, vibrant colors, professional quality, sharp throughout"Prompt Optimization Tips
Experiment with Variations
Try different phrasings:
- "A robot in a city" vs. "Urban robot scene" vs. "Futuristic android walking through metropolis"
Layer Details Gradually
Start simple, add complexity: 1. Basic: "A forest" 2. Enhanced: "A misty forest at dawn" 3. Detailed: "A mystical misty forest at dawn with rays of sunlight filtering through ancient trees"
Use Positive Phrasing
Focus on what you want, not what you don't want: ❌ "A landscape without people or buildings" ✓ "An untouched natural wilderness landscape"
Combine Modifiers
Stack quality and style terms: "Professional high-quality photorealistic portrait, studio lighting, 4K, sharp focus"
Reference Visual Elements
Use concrete visual descriptors:
- Instead of "pretty flowers" → "vibrant red roses with morning dew droplets"
- Instead of "nice building" → "modern glass skyscraper with reflective facade"
Common Pitfalls to Avoid
❌ Too vague: "A nice picture" ❌ Conflicting styles: "Photorealistic cartoon watercolor" ❌ Over-complicated: 500-word detailed prompt ❌ Too many subjects: "A cat, dog, bird, fish, hamster, and turtle" ❌ Negative instructions: "Don't make it dark or blurry"
✓ Clear and focused: "A playful golden retriever puppy in a sunny garden, natural photography"
Examples by Category
Nature
"Serene mountain lake at sunrise, mirror-like reflection, misty atmosphere, pine trees framing the scene, soft golden light, landscape photography, 16:9"Urban
"Cyberpunk city street at night, neon signs reflecting on wet pavement, dramatic perspective, vibrant blues and magentas, cinematic lighting, 9:16"Abstract
"Abstract geometric composition, bold color blocks in primary colors, minimalist design, clean lines, flat design aesthetic, 1:1"Portrait
"Professional portrait of a woman, natural window lighting, shallow depth of field, warm tones, 85mm lens, soft focus, editorial quality, 3:4"Illustration
"Whimsical children's book illustration of a friendly dragon, watercolor style, soft colors, playful composition, storybook aesthetic, 4:3"Resources
- Experiment in Google AI Studio for interactive testing
- See Imagen-specific prompting at Imagen docs
- General prompting strategies: Prompting guide
Gemini Image Generation Safety Settings
Comprehensive guide to configuring content safety filters for image generation.
Overview
The Gemini API includes adjustable safety filters to block potentially harmful content across multiple categories. Safety settings can be configured per-request to balance content filtering with your application's needs.
Safety Categories
The API filters content across 4 main categories:
| Category | Constant | Description |
|---|---|---|
| Harassment | HARM_CATEGORY_HARASSMENT | Negative or harmful comments targeting identity and/or protected attributes |
| Hate Speech | HARM_CATEGORY_HATE_SPEECH | Content that is rude, disrespectful, or profane |
| Sexually Explicit | HARM_CATEGORY_SEXUALLY_EXPLICIT | References to sexual acts or other lewd content |
| Dangerous Content | HARM_CATEGORY_DANGEROUS_CONTENT | Promotes, facilitates, or encourages harmful acts |
Note: Civic integrity and other categories are only available for Legacy PaLM 2 models, not Gemini models.
Block Thresholds
Configure how aggressively content is filtered:
| Threshold | Constant | Behavior |
|---|---|---|
| Off | OFF | Turn off safety filter completely |
| Block None | BLOCK_NONE | Show content regardless of probability |
| Block Few | BLOCK_ONLY_HIGH | Block only HIGH probability unsafe content |
| Block Some | BLOCK_MEDIUM_AND_ABOVE | Block MEDIUM and HIGH probability content |
| Block Most | BLOCK_LOW_AND_ABOVE | Block LOW, MEDIUM, and HIGH probability content |
| Unspecified | HARM_BLOCK_THRESHOLD_UNSPECIFIED | Use default threshold |
Probability Levels
Content is rated by probability of being unsafe:
- NEGLIGIBLE - Very unlikely to be harmful
- LOW - Low probability of harm
- MEDIUM - Moderate probability of harm
- HIGH - High probability of harm
Important: The API blocks based on probability, not severity. Low-probability content might still contain high-severity harm.
Default Behavior
Default Thresholds
- Newer stable GA models: Block none by default
- Other models: Block some (MEDIUM_AND_ABOVE) by default
- Google AI Studio: Cannot completely disable safety settings
Built-in Protections
Always blocked (cannot be configured):
- Child safety content
- Core harmful content categories
These protections cannot be disabled or adjusted.
Configuration Examples
Python SDK
from google import genai
from google.genai import types
client = genai.Client(api_key="your-api-key")
# Configure safety settings
config = types.GenerateContentConfig(
response_modalities=['image'],
aspect_ratio='16:9',
safety_settings=[
# Block only high-probability harassment
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_HARASSMENT,
threshold=types.HarmBlockThreshold.BLOCK_ONLY_HIGH
),
# Block medium and high hate speech
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
threshold=types.HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE
),
# Block all sexually explicit content
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
threshold=types.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE
),
# Block dangerous content
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
threshold=types.HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE
)
]
)
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents='Your prompt here',
config=config
)REST API
curl -X POST \
"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-image:generateContent" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [{
"parts": [{
"text": "Your prompt here"
}]
}],
"safetySettings": [
{
"category": "HARM_CATEGORY_HARASSMENT",
"threshold": "BLOCK_ONLY_HIGH"
},
{
"category": "HARM_CATEGORY_HATE_SPEECH",
"threshold": "BLOCK_MEDIUM_AND_ABOVE"
},
{
"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
"threshold": "BLOCK_LOW_AND_ABOVE"
},
{
"category": "HARM_CATEGORY_DANGEROUS_CONTENT",
"threshold": "BLOCK_MEDIUM_AND_ABOVE"
}
]
}'Reading Safety Feedback
Prompt Blocking
When a prompt is blocked:
response = client.models.generate_content(...)
# Check if prompt was blocked
if response.prompt_feedback:
if response.prompt_feedback.block_reason:
print(f"Prompt blocked: {response.prompt_feedback.block_reason}")
# View safety ratings
for rating in response.prompt_feedback.safety_ratings:
print(f"Category: {rating.category}")
print(f"Probability: {rating.probability}")Block reasons:
BLOCK_REASON_UNSPECIFIEDSAFETY- Blocked due to safety filtersOTHER- Other blocking reason
Response Blocking
When a response is blocked:
# Check finish reason
for candidate in response.candidates:
if candidate.finish_reason == 'SAFETY':
print("Response blocked due to safety filters")
# View detailed safety ratings
for rating in candidate.safety_ratings:
print(f"Category: {rating.category}")
print(f"Probability: {rating.probability}")
print(f"Blocked: {rating.blocked}")Full Safety Check Example
def check_safety(response):
"""Check if content was blocked and why"""
# Check prompt feedback
if response.prompt_feedback:
if response.prompt_feedback.block_reason:
print("⚠️ Prompt was blocked")
print(f"Reason: {response.prompt_feedback.block_reason}")
for rating in response.prompt_feedback.safety_ratings:
print(f" {rating.category}: {rating.probability}")
return False
# Check response candidates
if not response.candidates:
print("⚠️ No candidates returned")
return False
candidate = response.candidates[0]
if candidate.finish_reason == 'SAFETY':
print("⚠️ Response was blocked by safety filters")
for rating in candidate.safety_ratings:
if rating.blocked:
print(f" {rating.category}: {rating.probability} (BLOCKED)")
else:
print(f" {rating.category}: {rating.probability}")
return False
return True
# Usage
response = client.models.generate_content(...)
if check_safety(response):
# Process response
pass
else:
# Handle blocked content
passConfiguration Strategies
Permissive (Content Creation)
For creative applications where flexibility is important:
safety_settings=[
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_HARASSMENT,
threshold=types.HarmBlockThreshold.BLOCK_ONLY_HIGH
),
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
threshold=types.HarmBlockThreshold.BLOCK_ONLY_HIGH
),
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
threshold=types.HarmBlockThreshold.BLOCK_ONLY_HIGH
),
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
threshold=types.HarmBlockThreshold.BLOCK_ONLY_HIGH
)
]Balanced (General Use)
For general applications:
safety_settings=[
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_HARASSMENT,
threshold=types.HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE
),
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
threshold=types.HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE
),
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
threshold=types.HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE
),
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
threshold=types.HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE
)
]Restrictive (Public/Educational)
For public-facing or educational applications:
safety_settings=[
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_HARASSMENT,
threshold=types.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE
),
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
threshold=types.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE
),
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
threshold=types.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE
),
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
threshold=types.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE
)
]Category-Specific
Different thresholds for different categories:
safety_settings=[
# More permissive for harassment (artistic expression)
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_HARASSMENT,
threshold=types.HarmBlockThreshold.BLOCK_ONLY_HIGH
),
# Stricter for hate speech
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
threshold=types.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE
),
# Very strict for sexually explicit
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
threshold=types.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE
),
# Moderate for dangerous content
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
threshold=types.HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE
)
]Best Practices
Testing and Iteration
1. Start with defaults: Use default settings initially 2. Test edge cases: Try prompts that might trigger filters 3. Adjust incrementally: Make small changes to thresholds 4. Monitor feedback: Log safety ratings to understand patterns 5. Document decisions: Record why certain thresholds were chosen
Handling Blocked Content
def generate_with_retry(prompt, max_retries=3):
"""Generate image with automatic retry on safety blocks"""
for attempt in range(max_retries):
try:
response = client.models.generate_content(
model='gemini-2.5-flash-image',
contents=prompt,
config=config
)
# Check if blocked
if response.candidates[0].finish_reason == 'SAFETY':
print(f"Attempt {attempt + 1} blocked. Adjusting prompt...")
# Modify prompt or adjust safety settings
prompt = modify_prompt(prompt)
continue
return response
except Exception as e:
print(f"Error: {e}")
if attempt < max_retries - 1:
continue
raise
return NoneUser Communication
When content is blocked, provide clear feedback:
if candidate.finish_reason == 'SAFETY':
blocked_categories = [
rating.category
for rating in candidate.safety_ratings
if rating.blocked
]
message = f"Content generation was blocked due to: {', '.join(blocked_categories)}"
message += "\nPlease try a different prompt or contact support."
return {"error": message, "categories": blocked_categories}Regional Restrictions
Child Image Restrictions
Uploading images of children is restricted in:
- European Economic Area (EEA)
- Switzerland (CH)
- United Kingdom (UK)
Requests from these regions with child images will be rejected regardless of safety settings.
Compliance Considerations
Terms of Service
Applications using less restrictive safety settings may be subject to review per Google's Terms of Service.
Required:
- Review terms before deploying with custom settings
- Implement additional content moderation if needed
- Monitor usage for policy compliance
Responsible AI
Consider these factors when configuring safety:
1. User base: Who will use your application? 2. Use case: What is the application's purpose? 3. Context: Where will generated content appear? 4. Risk tolerance: What level of risk is acceptable? 5. Mitigation: What additional safeguards are in place?
Debugging Safety Issues
Common Issues
Issue: Legitimate content being blocked
Solution: 1. Check which category triggered the block 2. Review threshold for that category 3. Consider adjusting to next less restrictive level 4. Test with variations of the prompt
Issue: Inconsistent blocking
Solution: 1. Review probability levels (content near threshold) 2. Make prompts more specific 3. Add context to clarify intent 4. Use system instructions to set tone
Issue: Unable to generate certain content types
Solution: 1. Verify content doesn't violate core protections 2. Check regional restrictions 3. Review Terms of Service 4. Consider alternative approaches
Logging for Analysis
import json
from datetime import datetime
def log_safety_feedback(prompt, response):
"""Log safety feedback for analysis"""
log_entry = {
"timestamp": datetime.now().isoformat(),
"prompt": prompt,
"blocked": False,
"block_reason": None,
"safety_ratings": []
}
if response.prompt_feedback:
log_entry["block_reason"] = response.prompt_feedback.block_reason
log_entry["blocked"] = bool(response.prompt_feedback.block_reason)
for rating in response.prompt_feedback.safety_ratings:
log_entry["safety_ratings"].append({
"category": str(rating.category),
"probability": str(rating.probability),
"blocked": rating.blocked
})
if response.candidates:
candidate = response.candidates[0]
if candidate.finish_reason == 'SAFETY':
log_entry["blocked"] = True
# Write to log file
with open('safety_log.jsonl', 'a') as f:
f.write(json.dumps(log_entry) + '\n')
return log_entryResources
Related skills
FAQ
Which model does this skill use?
It uses Google's gemini-2.5-flash-image model for text-to-image generation and editing.
What aspect ratios are supported?
The docs list 1:1, 16:9, 9:16, 4:3, and 3:4, each costing 1290 tokens.
How many images can be composited?
The docs recommend combining up to 3 source images.