Crafting Effective Prompts for Image Generation in Java

Introduction to Crafting Effective Prompts

Welcome back! In the previous lesson, you learned how to generate a simple image using Google's Gemini API and its Flash Image model. Now, we will delve deeper into the art of crafting effective prompts to achieve the desired image outputs.

Crafting a well-thought-out prompt is crucial because it directly influences the quality and relevance of the generated image. In this lesson, we will explore the key components of a prompt: subject, context, and style. Understanding these components will empower you to create more detailed and specific prompts, leading to more accurate and visually appealing images.

Understanding Prompt Components

A prompt is essentially a textual description that guides the image generation process. It consists of three main components: subject, context, and style. The subject is the primary focus of the image, such as a cat or a landscape. The context provides additional details about the setting or environment, such as a bustling city at night. The style defines the artistic approach, such as digital art or watercolor painting. Each component plays a vital role in shaping the final image.

For example, a simple prompt such as "A cat" might generate a generic image of a cat. However, by adding context and style, such as "A black cat sitting on a windowsill overlooking a bustling city at night, in the style of digital art", you can create a more vivid and specific image. This detailed prompt provides the model with more information, resulting in a richer and more accurate output.

Example: Crafting and Testing Prompts

Let's walk through the Java code to see how different prompts affect the generated images. The code below uses the official Gemini Java client to call generateContent with the gemini-3.1-flash-image model. It retrieves the API key from an environment variable, constructs the request for each prompt, and saves the generated image to disk.

Java
package com.codesignal;

import com.google.genai.Client;
import com.google.genai.types.HttpOptions;
import com.google.genai.types.Content;
import com.google.genai.types.GenerateContentConfig;
import com.google.genai.types.GenerateContentResponse;
import com.google.genai.types.Part;

import java.io.FileOutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;

public class Main {
    public static void main(String[] args) throws Exception {
        String apiKey = System.getenv("GEMINI_API_KEY");
        String baseUrl = System.getenv("GEMINI_BASE_URL");

        Client client = new Client.Builder()
                .apiKey(apiKey)
                .httpOptions(HttpOptions.builder().baseUrl(baseUrl).apiVersion("v1beta").build())
                .build();

        // Define prompts with varying detail
        List<String> prompts = Arrays.asList(
            "A cat",
            "A black cat sitting on a windowsill",
            "A black cat sitting on a windowsill overlooking a bustling city at night, in the style of digital art",
            "A close-up of a black cat sitting on a windowsill overlooking a bustling city at night, in the style of digital art"
        );

        String outputDir = "public/images";
        Files.createDirectories(Paths.get(outputDir));

        for (String prompt : prompts) {
            GenerateContentResponse response = client.models.generateContent(
                "gemini-3.1-flash-image",
                prompt,
                GenerateContentConfig.builder()
                    .responseModalities(List.of("IMAGE"))
                    .build()
            );

            for (Part part : response.candidates().get().get(0).content().get().parts().get()) {
                if (part.inlineData().isPresent()) {
                    byte[] imageBytes = Base64.getDecoder().decode(part.inlineData().get().data().orElseThrow(() -> new RuntimeException("No data found")));

                    long timestamp = System.currentTimeMillis();
                    String imageFilename = "image_" + timestamp + ".png";
                    String outputPath = outputDir + "/" + imageFilename;
                    try (FileOutputStream fos = new FileOutputStream(outputPath)) {
                        fos.write(imageBytes);
                    }
                    System.out.println("Image written to: " + outputPath);
                }
            }
        }
    }
}

As you can see, the code iterates over each prompt, generating an image for each one. For every response, it walks through the returned parts and checks for inlineData — this is where the Gemini API delivers the generated image bytes directly.

The level of detail in the prompt directly affects the complexity and specificity of the generated image. By experimenting with different prompts, you can observe how the model interprets and visualizes the descriptions.

The use of timestamps in the file naming process serves two important purposes. First, it ensures that each generated image has a unique filename, preventing files from being overwritten when saved to the same directory. Second, the timestamp provides a simple and effective way to sort and track images by the order in which they were generated, which can be useful for debugging or analyzing model performance over time.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal