image_editing/
image_editing.rs

1use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
2use gemini_rust::Gemini;
3use std::env;
4use std::fs;
5
6/// Image editing example using Gemini API
7/// This demonstrates how to edit existing images using text prompts
8#[tokio::main]
9async fn main() -> Result<(), Box<dyn std::error::Error>> {
10    // Get API key from environment variable
11    let api_key = env::var("GEMINI_API_KEY").expect("GEMINI_API_KEY environment variable not set");
12
13    // Create client with the image generation model
14    let client = Gemini::with_model(api_key, "models/gemini-2.5-flash-image-preview".to_string());
15
16    println!("🎨 Image Editing with Gemini");
17    println!("This example shows how to edit images using text descriptions.");
18    println!();
19
20    // First, let's generate a base image to edit
21    println!("📸 Step 1: Generating a base image...");
22    let base_response = client
23        .generate_content()
24        .with_user_message(
25            "Create a simple landscape image with a blue sky, green grass, \
26             and a single white house in the center. The style should be \
27             clean and minimalist.",
28        )
29        .execute()
30        .await?;
31
32    // Save the base image
33    let mut base_image_data = None;
34    for candidate in base_response.candidates.iter() {
35        if let Some(parts) = &candidate.content.parts {
36            for part in parts.iter() {
37                if let gemini_rust::Part::InlineData { inline_data } = part {
38                    base_image_data = Some(inline_data.data.clone());
39                    let image_bytes = BASE64.decode(&inline_data.data)?;
40                    fs::write("base_landscape.png", image_bytes)?;
41                    println!("✅ Base image saved as: base_landscape.png");
42                    break;
43                }
44            }
45        }
46    }
47
48    let base_data = match base_image_data {
49        Some(data) => data,
50        None => {
51            println!("❌ Failed to generate base image");
52            return Ok(());
53        }
54    };
55
56    println!();
57    println!("🖌️  Step 2: Editing the image...");
58
59    // Example 1: Add elements to the image
60    println!("   Adding a red barn to the scene...");
61    let edit_response1 = client
62        .generate_content()
63        .with_user_message(
64            "Add a red barn to the left side of this landscape image. \
65             The barn should fit naturally into the scene and match \
66             the minimalist style. Keep everything else exactly the same.",
67        )
68        .with_inline_data(&base_data, "image/png")
69        .execute()
70        .await?;
71
72    save_generated_images(&edit_response1, "landscape_with_barn")?;
73
74    // Example 2: Change the weather/atmosphere
75    println!("   Changing the scene to sunset...");
76    let edit_response2 = client
77        .generate_content()
78        .with_user_message(
79            "Transform this landscape into a beautiful sunset scene. \
80             Change the sky to warm orange and pink colors, add a \
81             setting sun, and adjust the lighting to match golden hour. \
82             Keep the house and grass but make them glow with sunset light.",
83        )
84        .with_inline_data(&base_data, "image/png")
85        .execute()
86        .await?;
87
88    save_generated_images(&edit_response2, "sunset_landscape")?;
89
90    // Example 3: Style transfer
91    println!("   Converting to watercolor style...");
92    let edit_response3 = client
93        .generate_content()
94        .with_user_message(
95            "Transform this landscape into a watercolor painting style. \
96             Preserve the composition but render it with soft, flowing \
97             watercolor brushstrokes, gentle color bleeding, and the \
98             characteristic transparency of watercolor art.",
99        )
100        .with_inline_data(&base_data, "image/png")
101        .execute()
102        .await?;
103
104    save_generated_images(&edit_response3, "watercolor_landscape")?;
105
106    println!();
107    println!("🎉 Image editing examples completed!");
108    println!("Check the generated files:");
109    println!("   - base_landscape.png (original)");
110    println!("   - landscape_with_barn_*.png (with added barn)");
111    println!("   - sunset_landscape_*.png (sunset version)");
112    println!("   - watercolor_landscape_*.png (watercolor style)");
113
114    Ok(())
115}
116
117/// Helper function to save generated images from a response
118fn save_generated_images(
119    response: &gemini_rust::GenerationResponse,
120    prefix: &str,
121) -> Result<(), Box<dyn std::error::Error>> {
122    let mut image_count = 0;
123
124    for candidate in response.candidates.iter() {
125        if let Some(parts) = &candidate.content.parts {
126            for part in parts.iter() {
127                match part {
128                    gemini_rust::Part::Text { text, .. } => {
129                        if !text.trim().is_empty() {
130                            println!("   📝 Model says: {}", text.trim());
131                        }
132                    }
133                    gemini_rust::Part::InlineData { inline_data } => {
134                        image_count += 1;
135                        match BASE64.decode(&inline_data.data) {
136                            Ok(image_bytes) => {
137                                let filename = format!("{}_{}.png", prefix, image_count);
138                                fs::write(&filename, image_bytes)?;
139                                println!("   ✅ Edited image saved as: {}", filename);
140                            }
141                            Err(e) => {
142                                println!("   ❌ Failed to decode image: {}", e);
143                            }
144                        }
145                    }
146                    _ => {}
147                }
148            }
149        }
150    }
151
152    if image_count == 0 {
153        println!("   ⚠️  No images were generated for this edit");
154    }
155
156    Ok(())
157}