image_editing/
image_editing.rs1use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
2use gemini_rust::Gemini;
3use std::env;
4use std::fs;
5
6#[tokio::main]
9async fn main() -> Result<(), Box<dyn std::error::Error>> {
10 let api_key = env::var("GEMINI_API_KEY").expect("GEMINI_API_KEY environment variable not set");
12
13 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 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 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 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 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 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
117fn 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}