Skip to content

Commit 2f1a2ea

Browse files
feat(genai): Multimodal Image Reference Samples Migration to gemini-2.5-flash-image (#10336)
* feat(genai): migrate ImageGenWithText to gemini-2.5-flash-image - Update ImageGenWithText to use client.models.generateContent with gemini-2.5-flash-image - Update ImageGenerationIT with configurable bucket, safe cleanup, and testImageGenWithText validation - Temporarily ignore remaining deprecated Imagen capability tests pending migration * feat(genai): migrate multimodal image generation samples to gemini-2.5-flash-image - Update Canny, RawReference, Scribble, Style, and Subject reference samples to use client.models.generateContent with multimodal Part inputs - Upload generated image bytes directly to destination GCS bucket URI - Enable and un-ignore all tests in ImageGenerationIT * Update genai/snippets/src/main/java/genai/imagegeneration/ImageGenWithText.java Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * fix(genai): wrap long line in ImageGenRawReferenceWithTextAndImage to fix checkstyle * fix(genai): prevent IndexOutOfBounds in BoundingBoxWithTxtImg and add retry in ImageGenerationMmFlashIT * Prevent IndexOutOfBoundsException in BoundingBoxWithTxtImg Added a check to prevent IndexOutOfBoundsException when accessing box2d. * Trigger GitHub Actions --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent 7d6dabd commit 2f1a2ea

8 files changed

Lines changed: 253 additions & 227 deletions

‎genai/snippets/src/main/java/genai/boundingbox/BoundingBoxWithTxtImg.java‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,12 @@ public static void plotBoundingBoxes(String imageUrl, List<BoundingBox> bounding
9090
Color.ORANGE);
9191

9292
for (int i = 0; i < boundingBoxes.size(); i++) {
93-
BoundingBox boundingBox = boundingBoxes.get((i));
93+
BoundingBox boundingBox = boundingBoxes.get(i);
9494
List<Integer> box2d = boundingBox.getBox2d();
95+
// Prevents IndexOutOfBoundsException
96+
if (box2d == null || box2d.size() < 4) {
97+
continue;
98+
}
9599

96100
// Scale normalized coordinates (0-1000) to image dimensions.
97101
int topY = (int) (box2d.get(0) / 1000.0 * height);

‎genai/snippets/src/main/java/genai/imagegeneration/ImageGenCannyCtrlTypeWithTextAndImage.java‎

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,24 @@
1818

1919
// [START googlegenaisdk_imggen_canny_ctrl_type_with_txt_img]
2020

21+
import com.google.cloud.storage.BlobId;
22+
import com.google.cloud.storage.BlobInfo;
23+
import com.google.cloud.storage.Storage;
24+
import com.google.cloud.storage.StorageOptions;
2125
import com.google.genai.Client;
22-
import com.google.genai.types.ControlReferenceConfig;
23-
import com.google.genai.types.ControlReferenceImage;
24-
import com.google.genai.types.EditImageConfig;
25-
import com.google.genai.types.EditImageResponse;
26-
import com.google.genai.types.GeneratedImage;
27-
import com.google.genai.types.Image;
28-
import java.util.List;
26+
import com.google.genai.types.Blob;
27+
import com.google.genai.types.Candidate;
28+
import com.google.genai.types.Content;
29+
import com.google.genai.types.GenerateContentConfig;
30+
import com.google.genai.types.GenerateContentResponse;
31+
import com.google.genai.types.Part;
2932
import java.util.Optional;
3033

3134
public class ImageGenCannyCtrlTypeWithTextAndImage {
3235

3336
public static void main(String[] args) {
3437
// TODO(developer): Replace these variables before running the sample.
35-
String modelId = "imagen-3.0-capability-001";
38+
String modelId = "gemini-2.5-flash-image";
3639
String outputGcsUri = "gs://your-bucket/your-prefix";
3740
cannyEdgeCustomization(modelId, outputGcsUri);
3841
}
@@ -41,44 +44,48 @@ public static void main(String[] args) {
4144
public static Optional<String> cannyEdgeCustomization(String modelId, String outputGcsUri) {
4245
// Client Initialization. Once created, it can be reused for multiple requests.
4346
try (Client client = Client.builder().location("global").vertexAI(true).build()) {
44-
// Create a reference image out of an existing canny edge image signal
45-
// using https://storage.googleapis.com/cloud-samples-data/generative-ai/image/car_canny.png
46-
ControlReferenceImage controlReferenceImage =
47-
ControlReferenceImage.builder()
48-
.referenceId(1)
49-
.referenceImage(
50-
Image.builder()
51-
.gcsUri("gs://cloud-samples-data/generative-ai/image/car_canny.png")
52-
.build())
53-
.config(ControlReferenceConfig.builder().controlType("CONTROL_TYPE_CANNY").build())
54-
.build();
5547

56-
// The `[1]` in the prompt refers to the `referenceId` assigned to
57-
// the control reference image.
58-
EditImageResponse imageResponse =
59-
client.models.editImage(
48+
GenerateContentConfig config =
49+
GenerateContentConfig.builder().responseModalities("TEXT", "IMAGE").build();
50+
51+
GenerateContentResponse response =
52+
client.models.generateContent(
6053
modelId,
61-
"a watercolor painting of a red car[1] driving on a road",
62-
List.of(controlReferenceImage),
63-
EditImageConfig.builder()
64-
.editMode("EDIT_MODE_CONTROLLED_EDITING")
65-
.numberOfImages(1)
66-
.safetyFilterLevel("BLOCK_MEDIUM_AND_ABOVE")
67-
.personGeneration("ALLOW_ADULT")
68-
.outputGcsUri(outputGcsUri)
69-
.build());
54+
Content.fromParts(
55+
Part.fromUri(
56+
"gs://cloud-samples-data/generative-ai/image/car_canny.png", "image/png"),
57+
Part.fromText("a watercolor painting of a red car driving on a road")),
58+
config);
7059

71-
Image generatedImage =
72-
imageResponse
73-
.generatedImages()
74-
.flatMap(generatedImages -> generatedImages.stream().findFirst())
75-
.flatMap(GeneratedImage::image)
60+
byte[] imageBytes =
61+
response
62+
.candidates()
63+
.flatMap(candidates -> candidates.stream().findFirst())
64+
.flatMap(Candidate::content)
65+
.flatMap(Content::parts)
66+
.flatMap(
67+
parts ->
68+
parts.stream()
69+
.filter(part -> part.inlineData().flatMap(Blob::data).isPresent())
70+
.findFirst())
71+
.flatMap(part -> part.inlineData().flatMap(Blob::data))
7672
.orElseThrow(() -> new IllegalStateException("No image was generated by the model."));
7773

78-
generatedImage.gcsUri().ifPresent(System.out::println);
79-
// Example response:
80-
// gs://your-bucket/your-prefix
81-
return generatedImage.gcsUri();
74+
Storage storage = StorageOptions.getDefaultInstance().getService();
75+
String gcsPath = outputGcsUri.replace("gs://", "");
76+
int slashIdx = gcsPath.indexOf('/');
77+
String bucket = slashIdx > 0 ? gcsPath.substring(0, slashIdx) : gcsPath;
78+
String objectName =
79+
slashIdx > 0
80+
? gcsPath.substring(slashIdx + 1) + "/canny_customization.png"
81+
: "canny_customization.png";
82+
BlobId blobId = BlobId.of(bucket, objectName);
83+
BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setContentType("image/png").build();
84+
storage.create(blobInfo, imageBytes);
85+
86+
String fullGcsUri = String.format("gs://%s/%s", bucket, objectName);
87+
System.out.println("Generated image URI: " + fullGcsUri);
88+
return Optional.of(fullGcsUri);
8289
}
8390
}
8491
}

‎genai/snippets/src/main/java/genai/imagegeneration/ImageGenRawReferenceWithTextAndImage.java‎

Lines changed: 50 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,24 @@
1818

1919
// [START googlegenaisdk_imggen_raw_reference_with_txt_img]
2020

21+
import com.google.cloud.storage.BlobId;
22+
import com.google.cloud.storage.BlobInfo;
23+
import com.google.cloud.storage.Storage;
24+
import com.google.cloud.storage.StorageOptions;
2125
import com.google.genai.Client;
22-
import com.google.genai.types.EditImageConfig;
23-
import com.google.genai.types.EditImageResponse;
24-
import com.google.genai.types.GeneratedImage;
25-
import com.google.genai.types.Image;
26-
import com.google.genai.types.RawReferenceImage;
27-
import java.util.List;
26+
import com.google.genai.types.Blob;
27+
import com.google.genai.types.Candidate;
28+
import com.google.genai.types.Content;
29+
import com.google.genai.types.GenerateContentConfig;
30+
import com.google.genai.types.GenerateContentResponse;
31+
import com.google.genai.types.Part;
2832
import java.util.Optional;
2933

3034
public class ImageGenRawReferenceWithTextAndImage {
3135

3236
public static void main(String[] args) {
3337
// TODO(developer): Replace these variables before running the sample.
34-
String modelId = "imagen-3.0-capability-001";
38+
String modelId = "gemini-2.5-flash-image";
3539
String outputGcsUri = "gs://your-bucket/your-prefix";
3640
styleTransferCustomization(modelId, outputGcsUri);
3741
}
@@ -41,43 +45,50 @@ public static void main(String[] args) {
4145
public static Optional<String> styleTransferCustomization(String modelId, String outputGcsUri) {
4246
// Client Initialization. Once created, it can be reused for multiple requests.
4347
try (Client client = Client.builder().location("global").vertexAI(true).build()) {
44-
// Create a raw reference image of teacup stored in Google Cloud Storage
45-
// using https://storage.googleapis.com/cloud-samples-data/generative-ai/image/teacup-1.png
46-
RawReferenceImage rawReferenceImage =
47-
RawReferenceImage.builder()
48-
.referenceId(1)
49-
.referenceImage(
50-
Image.builder()
51-
.gcsUri("gs://cloud-samples-data/generative-ai/image/teacup-1.png")
52-
.build())
53-
.build();
5448

55-
// The `[1]` in the prompt refers to the `referenceId` assigned to the raw reference image.
56-
EditImageResponse imageResponse =
57-
client.models.editImage(
49+
GenerateContentConfig config =
50+
GenerateContentConfig.builder().responseModalities("TEXT", "IMAGE").build();
51+
52+
GenerateContentResponse response =
53+
client.models.generateContent(
5854
modelId,
59-
"transform the subject in the image so that "
60-
+ "the teacup[1] is made entirely out of chocolate",
61-
List.of(rawReferenceImage),
62-
EditImageConfig.builder()
63-
.editMode("EDIT_MODE_DEFAULT")
64-
.numberOfImages(1)
65-
.safetyFilterLevel("BLOCK_MEDIUM_AND_ABOVE")
66-
.personGeneration("ALLOW_ADULT")
67-
.outputGcsUri(outputGcsUri)
68-
.build());
55+
Content.fromParts(
56+
Part.fromUri(
57+
"gs://cloud-samples-data/generative-ai/image/teacup-1.png", "image/png"),
58+
Part.fromText(
59+
"transform the subject in the image so that "
60+
+ "the teacup is made entirely out of chocolate")),
61+
config);
6962

70-
Image generatedImage =
71-
imageResponse
72-
.generatedImages()
73-
.flatMap(generatedImages -> generatedImages.stream().findFirst())
74-
.flatMap(GeneratedImage::image)
63+
byte[] imageBytes =
64+
response
65+
.candidates()
66+
.flatMap(candidates -> candidates.stream().findFirst())
67+
.flatMap(Candidate::content)
68+
.flatMap(Content::parts)
69+
.flatMap(
70+
parts ->
71+
parts.stream()
72+
.filter(part -> part.inlineData().flatMap(Blob::data).isPresent())
73+
.findFirst())
74+
.flatMap(part -> part.inlineData().flatMap(Blob::data))
7575
.orElseThrow(() -> new IllegalStateException("No image was generated by the model."));
7676

77-
generatedImage.gcsUri().ifPresent(System.out::println);
78-
// Example response:
79-
// gs://your-bucket/your-prefix
80-
return generatedImage.gcsUri();
77+
Storage storage = StorageOptions.getDefaultInstance().getService();
78+
String gcsPath = outputGcsUri.replace("gs://", "");
79+
int slashIdx = gcsPath.indexOf('/');
80+
String bucket = slashIdx > 0 ? gcsPath.substring(0, slashIdx) : gcsPath;
81+
String objectName =
82+
slashIdx > 0
83+
? gcsPath.substring(slashIdx + 1) + "/raw_reference.png"
84+
: "raw_reference.png";
85+
BlobId blobId = BlobId.of(bucket, objectName);
86+
BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setContentType("image/png").build();
87+
storage.create(blobInfo, imageBytes);
88+
89+
String fullGcsUri = String.format("gs://%s/%s", bucket, objectName);
90+
System.out.println("Generated image URI: " + fullGcsUri);
91+
return Optional.of(fullGcsUri);
8192
}
8293
}
8394
}

‎genai/snippets/src/main/java/genai/imagegeneration/ImageGenScribbleCtrlTypeWithTextAndImage.java‎

Lines changed: 47 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,24 @@
1818

1919
// [START googlegenaisdk_imggen_scribble_ctrl_type_with_txt_img]
2020

21+
import com.google.cloud.storage.BlobId;
22+
import com.google.cloud.storage.BlobInfo;
23+
import com.google.cloud.storage.Storage;
24+
import com.google.cloud.storage.StorageOptions;
2125
import com.google.genai.Client;
22-
import com.google.genai.types.ControlReferenceConfig;
23-
import com.google.genai.types.ControlReferenceImage;
24-
import com.google.genai.types.EditImageConfig;
25-
import com.google.genai.types.EditImageResponse;
26-
import com.google.genai.types.GeneratedImage;
27-
import com.google.genai.types.Image;
28-
import java.util.List;
26+
import com.google.genai.types.Blob;
27+
import com.google.genai.types.Candidate;
28+
import com.google.genai.types.Content;
29+
import com.google.genai.types.GenerateContentConfig;
30+
import com.google.genai.types.GenerateContentResponse;
31+
import com.google.genai.types.Part;
2932
import java.util.Optional;
3033

3134
public class ImageGenScribbleCtrlTypeWithTextAndImage {
3235

3336
public static void main(String[] args) {
3437
// TODO(developer): Replace these variables before running the sample.
35-
String modelId = "imagen-3.0-capability-001";
38+
String modelId = "gemini-2.5-flash-image";
3639
String outputGcsUri = "gs://your-bucket/your-prefix";
3740
scribbleCustomization(modelId, outputGcsUri);
3841
}
@@ -41,46 +44,48 @@ public static void main(String[] args) {
4144
public static Optional<String> scribbleCustomization(String modelId, String outputGcsUri) {
4245
// Client Initialization. Once created, it can be reused for multiple requests.
4346
try (Client client = Client.builder().location("global").vertexAI(true).build()) {
44-
// Create a reference image out of an existing scribble image signal
45-
// using
46-
// https://storage.googleapis.com/cloud-samples-data/generative-ai/image/car_scribble.png
47-
ControlReferenceImage controlReferenceImage =
48-
ControlReferenceImage.builder()
49-
.referenceId(1)
50-
.referenceImage(
51-
Image.builder()
52-
.gcsUri("gs://cloud-samples-data/generative-ai/image/car_scribble.png")
53-
.build())
54-
.config(ControlReferenceConfig.builder().controlType("CONTROL_TYPE_SCRIBBLE").build())
55-
.build();
5647

57-
// The `[1]` in the prompt refers to the `referenceId` assigned to the
58-
// control reference image.
59-
EditImageResponse imageResponse =
60-
client.models.editImage(
48+
GenerateContentConfig config =
49+
GenerateContentConfig.builder().responseModalities("TEXT", "IMAGE").build();
50+
51+
GenerateContentResponse response =
52+
client.models.generateContent(
6153
modelId,
62-
"an oil painting showing the side of a red car[1]",
63-
List.of(controlReferenceImage),
64-
EditImageConfig.builder()
65-
.editMode("EDIT_MODE_CONTROLLED_EDITING")
66-
.numberOfImages(1)
67-
.safetyFilterLevel("BLOCK_MEDIUM_AND_ABOVE")
68-
.personGeneration("ALLOW_ADULT")
69-
.outputGcsUri(outputGcsUri)
70-
.build());
54+
Content.fromParts(
55+
Part.fromUri(
56+
"gs://cloud-samples-data/generative-ai/image/car_scribble.png", "image/png"),
57+
Part.fromText("an oil painting showing the side of a red car")),
58+
config);
7159

72-
Image generatedImage =
73-
imageResponse
74-
.generatedImages()
75-
.flatMap(generatedImages -> generatedImages.stream().findFirst())
76-
.flatMap(GeneratedImage::image)
60+
byte[] imageBytes =
61+
response
62+
.candidates()
63+
.flatMap(candidates -> candidates.stream().findFirst())
64+
.flatMap(Candidate::content)
65+
.flatMap(Content::parts)
66+
.flatMap(
67+
parts ->
68+
parts.stream()
69+
.filter(part -> part.inlineData().flatMap(Blob::data).isPresent())
70+
.findFirst())
71+
.flatMap(part -> part.inlineData().flatMap(Blob::data))
7772
.orElseThrow(() -> new IllegalStateException("No image was generated by the model."));
7873

79-
generatedImage.gcsUri().ifPresent(System.out::println);
80-
// Example response:
81-
// gs://your-bucket/your-prefix
74+
Storage storage = StorageOptions.getDefaultInstance().getService();
75+
String gcsPath = outputGcsUri.replace("gs://", "");
76+
int slashIdx = gcsPath.indexOf('/');
77+
String bucket = slashIdx > 0 ? gcsPath.substring(0, slashIdx) : gcsPath;
78+
String objectName =
79+
slashIdx > 0
80+
? gcsPath.substring(slashIdx + 1) + "/scribble_customization.png"
81+
: "scribble_customization.png";
82+
BlobId blobId = BlobId.of(bucket, objectName);
83+
BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setContentType("image/png").build();
84+
storage.create(blobInfo, imageBytes);
8285

83-
return generatedImage.gcsUri();
86+
String fullGcsUri = String.format("gs://%s/%s", bucket, objectName);
87+
System.out.println("Generated image URI: " + fullGcsUri);
88+
return Optional.of(fullGcsUri);
8489
}
8590
}
8691
}

0 commit comments

Comments
 (0)