Skip to main content

Image Generation

The Go AI SDK provides the ai.GenerateImage() function to generate images based on a given prompt using an image model.

package main

import (
"context"
"fmt"
"log"
"os"

"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/openai"
)

func main() {
ctx := context.Background()

provider := openai.New(openai.Config{APIKey: os.Getenv("OPENAI_API_KEY")})
imageModel, _ := provider.ImageModel("dall-e-3")

result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
})
if err != nil {
log.Fatal(err)
}

// Access image data
fmt.Printf("Image MIME type: %s\n", result.Image.MediaType)
fmt.Printf("Image size: %d bytes\n", len(result.Image.Data))

// Save image to file
err = os.WriteFile("generated.png", result.Image.Data, 0644)
if err != nil {
log.Fatal(err)
}

fmt.Println("Image saved to generated.png")
}

You can access the image data in different formats:

// As bytes
imageBytes := result.Image.Data

// As base64 string
base64String := result.Image.Base64()

// Get image MIME type
mimeType := result.Image.MediaType

Settings​

Size and Aspect Ratio​

Depending on the model, you can specify either the size or the aspect ratio.

Size​

The size is specified as a string in the format {width}x{height}. Models only support specific sizes, and the supported sizes vary by model and provider.

result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
Size: "1024x1024",
})

Aspect Ratio​

The aspect ratio is specified as a string in the format {width}:{height}. Models only support specific aspect ratios, which vary by model and provider.

provider := google.New(google.Config{APIKey: os.Getenv("GOOGLE_GENERATIVE_AI_API_KEY")})
imageModel, _ := provider.ImageModel("imagen-4.0-generate-001")

result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
Size: "1920x1080", // Automatically converts to 16:9 aspect ratio
})

Generating Multiple Images​

GenerateImage supports generating multiple images at once:

n := 4 // Number of images to generate

result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
N: &n,
})
if err != nil {
log.Fatal(err)
}

// Access all images
for i, image := range result.Images {
filename := fmt.Sprintf("image-%d.png", i+1)
err := os.WriteFile(filename, image.Data, 0644)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Saved %s\n", filename)
}

Note: GenerateImage will automatically batch requests as needed to generate the requested number of images.

Each image model has an internal limit on how many images it can generate in a single API call. The SDK manages this automatically by batching requests appropriately. By default, the SDK uses provider-documented limits (e.g., DALL-E 3 can only generate 1 image per call, while DALL-E 2 supports up to 10).

You can override this behavior using MaxImagesPerCall:

n := 10 // Will make 2 calls of 5 images each

result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
MaxImagesPerCall: 5, // Override default batch size
N: &n,
})

Providing a Seed​

You can provide a seed to control the output of the image generation process. If supported by the model, the same seed will always produce the same image.

seed := 1234567890

result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
Seed: &seed,
})

Provider-Specific Settings​

Image models often have provider- or model-specific settings. You can pass such settings using the ProviderOptions parameter:

result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
Size: "1024x1024",
ProviderOptions: map[string]interface{}{
"openai": map[string]interface{}{
"style": "vivid",
"quality": "hd",
},
},
})

Timeouts with Context​

Use Go's context for timeouts and cancellation:

// Timeout after 60 seconds
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()

result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
})
if err != nil {
if ctx.Err() == context.DeadlineExceeded {
fmt.Println("Image generation timed out")
}
log.Fatal(err)
}

Custom Headers​

Add custom headers to the image generation request:

result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
Headers: map[string]string{
"X-Custom-Header": "custom-value",
},
})

Warnings​

If the model returns warnings, they will be available in the Warnings field:

result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
})
if err != nil {
log.Fatal(err)
}

for _, warning := range result.Warnings {
fmt.Printf("Warning: %s\n", warning.Message)
}

Additional Provider Metadata​

Some providers expose additional metadata for the result:

result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Santa Claus driving a Cadillac",
})
if err != nil {
log.Fatal(err)
}

// Access provider-specific metadata
if metadata, ok := result.ProviderMetadata["openai"].(map[string]interface{}); ok {
if images, ok := metadata["images"].([]interface{}); ok && len(images) > 0 {
if imageMetadata, ok := images[0].(map[string]interface{}); ok {
if revisedPrompt, ok := imageMetadata["revisedPrompt"].(string); ok {
fmt.Printf("Original prompt: %s\n", "Santa Claus driving a Cadillac")
fmt.Printf("Revised prompt: %s\n", revisedPrompt)
}
}
}
}

Error Handling​

Handle image generation errors:

import providererrors "github.com/digitallysavvy/go-ai/pkg/provider/errors"

result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Generate an image",
})
if err != nil {
// Check for specific error types
var noImageErr *ai.NoImageGeneratedError
var rateLimitErr *providererrors.RateLimitError
if errors.As(err, &noImageErr) {
fmt.Println("No image was generated")
} else if errors.As(err, &rateLimitErr) {
fmt.Println("Rate limit exceeded")
} else {
fmt.Printf("Error: %v\n", err)
}
return
}

Practical Examples​

Saving Images in Different Formats​

func saveImage(image []byte, mimeType string, filename string) error {
ext := "png"
if mimeType == "image/jpeg" {
ext = "jpg"
}

return os.WriteFile(fmt.Sprintf("%s.%s", filename, ext), image, 0644)
}

result, _ := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: "Beautiful sunset",
})

saveImage(result.Image.Data, result.Image.MediaType, "sunset")

Generating Image Variations​

Generate multiple variations of the same prompt:

func generateVariations(ctx context.Context, model provider.ImageModel, prompt string, count int) ([]types.GeneratedFile, error) {
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: model,
Prompt: prompt,
N: &count,
})
if err != nil {
return nil, err
}

return result.Images, nil
}

images, _ := generateVariations(ctx, imageModel, "Abstract art with vibrant colors", 4)

for i, img := range images {
os.WriteFile(fmt.Sprintf("variation-%d.png", i+1), img.Data, 0644)
}

Batch Image Generation​

Generate multiple different images:

prompts := []string{
"A serene mountain landscape",
"A bustling city street at night",
"An underwater coral reef",
"A cozy coffee shop interior",
}

for i, prompt := range prompts {
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imageModel,
Prompt: prompt,
})
if err != nil {
log.Printf("Error generating image %d: %v\n", i+1, err)
continue
}

filename := fmt.Sprintf("batch-%d.png", i+1)
os.WriteFile(filename, result.Image.Data, 0644)
fmt.Printf("Generated %s: %s\n", filename, prompt)
}

Image Generation with Retry Logic​

func generateImageWithRetry(ctx context.Context, model provider.ImageModel, prompt string, maxRetries int) (*ai.GenerateImageResult, error) {
var lastErr error

for attempt := 0; attempt <= maxRetries; attempt++ {
if attempt > 0 {
fmt.Printf("Retry attempt %d/%d\n", attempt, maxRetries)
time.Sleep(time.Duration(attempt) * time.Second)
}

result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: model,
Prompt: prompt,
})

if err == nil {
return result, nil
}

lastErr = err

// Don't retry on certain errors
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
break
}
}

return nil, fmt.Errorf("failed after %d attempts: %w", maxRetries+1, lastErr)
}

Google Image Generation Examples​

Google Generative AI - Imagen 4.0​

// High-quality image generation with Imagen 4.0
googleProvider := google.New(google.Config{
APIKey: os.Getenv("GOOGLE_GENERATIVE_AI_API_KEY"),
})

imagenModel, _ := googleProvider.ImageModel("imagen-4.0-generate-001")

n := 1
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imagenModel,
Prompt: "A serene mountain landscape at sunset with dramatic clouds",
N: &n,
Size: "1024x1024", // Square 1:1 aspect ratio
})
if err != nil {
log.Fatal(err)
}

os.WriteFile("imagen_4_output.png", result.Image.Data, 0644)
fmt.Printf("Generated with Imagen 4.0: %d bytes\n", len(result.Image.Data))

Google Generative AI - Gemini Flash Image​

// Fast image generation with Gemini
geminiModel, _ := googleProvider.ImageModel("gemini-2.5-flash-image")

result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: geminiModel,
Prompt: "Abstract colorful art with geometric shapes and vibrant patterns",
Size: "1920x1080", // Widescreen 16:9
})
if err != nil {
log.Fatal(err)
}

os.WriteFile("gemini_output.png", result.Image.Data, 0644)

Google Vertex AI - Imagen 3.0​

// Enterprise-grade image generation with Vertex AI
vertexProvider, err := googlevertex.New(googlevertex.Config{
Project: os.Getenv("GOOGLE_VERTEX_PROJECT"),
Location: os.Getenv("GOOGLE_VERTEX_LOCATION"),
AccessToken: os.Getenv("GOOGLE_VERTEX_ACCESS_TOKEN"),
})
if err != nil {
log.Fatal(err)
}

vertexModel, _ := vertexProvider.ImageModel("imagen-3.0-generate-001")

n := 1
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: vertexModel,
Prompt: "A futuristic cityscape at night with neon lights",
N: &n,
Size: "1920x1080", // 16:9 aspect ratio
})
if err != nil {
log.Fatal(err)
}

os.WriteFile("vertex_imagen_output.png", result.Image.Data, 0644)

Comparing Google Models​

prompts := []string{
"A magical forest with glowing mushrooms",
"Cyberpunk city street at night",
"Mountain landscape with aurora borealis",
}

models := map[string]provider.ImageModel{
"imagen-4.0": imagenModel,
"gemini-flash": geminiModel,
"vertex-imagen": vertexModel,
}

for name, model := range models {
for i, prompt := range prompts {
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: model,
Prompt: prompt,
Size: "1024x1024",
})
if err != nil {
log.Printf("Error with %s: %v\n", name, err)
continue
}

filename := fmt.Sprintf("%s_%d.png", name, i+1)
os.WriteFile(filename, result.Image.Data, 0644)
fmt.Printf("✓ Generated %s\n", filename)
}
}

Image Models​

Several providers offer image generation models:

ProviderModelSupported Sizes/Aspect Ratios
xAIgrok-imagine-imageFlexible aspect ratios (1:1, 16:9, 9:16, 4:3, etc.)
OpenAIgpt-image-11024x1024, 1536x1024, 1024x1536
OpenAIdall-e-31024x1024, 1792x1024, 1024x1792
OpenAIdall-e-2256x256, 512x512, 1024x1024
Amazon Bedrockamazon.nova-canvas-v1:0320-4096 (multiples of 16)
Falfal-ai/flux/dev1:1, 3:4, 4:3, 9:16, 16:9, 9:21, 21:9
Falfal-ai/flux-pro/v1.1-ultra1:1, 3:4, 4:3, 9:16, 16:9, 9:21, 21:9
Googleimagen-4.0-generate-0011:1, 3:4, 4:3, 9:16, 16:9
Googlegemini-2.5-flash-image1:1, 3:4, 4:3, 9:16, 16:9
Google Verteximagen-3.0-generate-0011:1, 3:4, 4:3, 9:16, 16:9
Black Forest Labsflux-pro-1.1-ultra3:7 to 7:3 aspect ratios
Stability AIVarious via providersMultiple sizes supported

Example with Different Providers​

// XAI (Grok)
xaiProvider := xai.New(xai.Config{APIKey: os.Getenv("XAI_API_KEY")})
grokModel, _ := xaiProvider.ImageModel("grok-imagine-image")

// OpenAI
openaiProvider := openai.New(openai.Config{APIKey: os.Getenv("OPENAI_API_KEY")})
dalleModel, _ := openaiProvider.ImageModel("dall-e-3")

// Google Generative AI - Imagen 4.0
googleProvider := google.New(google.Config{APIKey: os.Getenv("GOOGLE_GENERATIVE_AI_API_KEY")})
imagenModel, _ := googleProvider.ImageModel("imagen-4.0-generate-001")

// Google Generative AI - Gemini Image
geminiImageModel, _ := googleProvider.ImageModel("gemini-2.5-flash-image")

// Google Vertex AI - Imagen 3.0
vertexProvider, _ := googlevertex.New(googlevertex.Config{
Project: os.Getenv("GOOGLE_VERTEX_PROJECT"),
Location: os.Getenv("GOOGLE_VERTEX_LOCATION"),
AccessToken: os.Getenv("GOOGLE_VERTEX_ACCESS_TOKEN"),
})
vertexImagenModel, _ := vertexProvider.ImageModel("imagen-3.0-generate-001")

// Fal
falProvider := fal.New(fal.Config{APIKey: os.Getenv("FAL_API_KEY")})
fluxModel, _ := falProvider.ImageModel("fal-ai/flux/dev")

// Use any model with the same API
result, _ := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: imagenModel, // or grokModel, dalleModel, geminiImageModel, vertexImagenModel, or fluxModel
Prompt: "A beautiful landscape",
})

Advanced Features​

Image Editing​

Some providers support editing existing images with natural language instructions:

// XAI image editing
imageData, _ := os.ReadFile("source.jpg")

result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: grokModel,
Prompt: "Change the sky to vibrant sunset colors",
Files: []provider.ImageFile{
{
Type: "file",
Data: imageData,
MediaType: "image/jpeg",
},
},
})

Checking File and Mask Support​

Not every model that accepts Files / Mask actually consumes them for editing; some silently ignore them and return an unrelated fresh generation. A model can optionally advertise support through SupportsFileInputs() *bool / SupportsMaskInputs() *bool, read via provider.ImageModelSupportsFileInputs / provider.ImageModelSupportsMaskInputs. nil means unknown — only route an editing request to a model when the result is a non-nil true:

if supported := provider.ImageModelSupportsFileInputs(model); supported != nil && *supported {
// safe to pass Files for image editing
}

Image Inpainting​

Fill specific areas of an image with new content using masks:

sourceImage, _ := os.ReadFile("source.jpg")
maskImage, _ := os.ReadFile("mask.png")

result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: grokModel,
Prompt: "Add a rainbow in the masked area",
Files: []provider.ImageFile{
{Type: "file", Data: sourceImage, MediaType: "image/jpeg"},
},
Mask: &provider.ImageFile{
Type: "file",
Data: maskImage,
MediaType: "image/png",
},
})

Mask Requirements:

  • White pixels (255,255,255) indicate areas to modify
  • Black pixels (0,0,0) indicate areas to preserve
  • Mask should match source image dimensions

Image Variations​

Generate multiple variations of a source image:

sourceImage, _ := os.ReadFile("source.jpg")
n := 4

result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: grokModel,
Prompt: "Generate creative variations with different styles",
N: &n,
Files: []provider.ImageFile{
{Type: "file", Data: sourceImage, MediaType: "image/jpeg"},
},
})

Providers that can return multiple images expose every image through result.Images. Low-level provider results also preserve provider-returned base64 strings in result.Base64Images; the high-level ai.GenerateImage helper decodes those strings into GeneratedFile.Data so JSON output contains the expected base64 image data.

Best Practices​

  1. Set Timeouts: Image generation can be slow; always use context with timeout
  2. Handle Errors: Implement proper error handling and retry logic
  3. Validate Prompts: Ensure prompts are appropriate and within provider guidelines
  4. Choose Right Model: Different models excel at different styles and use cases
  5. Use Appropriate Sizes: Request sizes supported by the model
  6. Save Efficiently: Use appropriate image formats and compression
  7. Monitor Costs: Track image generation usage and costs
  8. Respect Rate Limits: Implement rate limiting for bulk generation
  9. Cache Results: Cache generated images when appropriate
  10. Test Prompts: Iterate on prompts to get desired results

Next Steps​

See Also​