-
Notifications
You must be signed in to change notification settings - Fork 776
Add Full Solo Imagen Editing Sample #109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Summary of ChangesHello @madebymozart, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a new, fully functional Imagen editing sample application for Android. It demonstrates how to generate images from textual descriptions using the Firebase Imagen API and then interactively edit parts of these images through an inpainting process, where users can draw masks to specify areas for modification. The changes span across new modules for the application, the sample itself, and shared UI components, setting up a robust environment for AI-powered image manipulation. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request adds a new sample for Imagen Editing. The overall structure is good, with separate modules for the app, the sample logic, and reusable UI components. However, there are several critical TODOs left in the code that leave the main features of the sample unimplemented. The inpainting data source call, the mask drawing gesture handling, and the ViewModel logic for inpainting are all missing. These need to be implemented for the sample to be functional. There are also some other issues regarding hardcoded strings, build configurations, and logging practices that should be addressed.
| suspend fun inpaintImage(sourceImage: Bitmap, maskImage: Bitmap, prompt: String, editSteps: Int = DEFAULT_EDIT_STEPS): Bitmap { | ||
| // TODO #1 - Implement data source for inpainting; | ||
| return sourceImage; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The inpaintImage function, which is a core part of this sample, is currently a stub. It needs to be implemented to call the Firebase Imagen API for inpainting.
suspend fun inpaintImage(sourceImage: Bitmap, maskImage: Bitmap, prompt: String, editSteps: Int = DEFAULT_EDIT_STEPS): Bitmap {
val imageResponse = editingModel.editImage(
prompt = prompt,
image = ImagenRawImage(sourceImage),
mask = ImagenRawMask(maskImage),
editingConfig = ImagenEditingConfig(
editMode = ImagenEditMode.Inpainting(editSteps = editSteps)
)
)
val image = imageResponse.images.first()
return image.asBitmap()
}| detectDragGestures( | ||
| // TODO #2 - Implement Drag logic | ||
| onDragStart = { startOffset -> | ||
| }, | ||
| onDrag = { change, _ -> | ||
| }, | ||
| onDragEnd = { | ||
| }, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The drag gesture handling for drawing the mask is not implemented. This is essential for the user to be able to create a mask for inpainting. The onDragStart, onDrag, and onDragEnd callbacks should be implemented to handle path drawing.
detectDragGestures(
onDragStart = { startOffset ->
val transformedOffset = Offset(
(startOffset.x - offsetX) / scale,
(startOffset.y - offsetY) / scale
)
currentPath = Path().apply {
moveTo(transformedOffset.x, transformedOffset.y)
}
},
onDrag = { change, _ ->
val transformedOffset = Offset(
(change.position.x - offsetX) / scale,
(change.position.y - offsetY) / scale
)
currentPath?.lineTo(transformedOffset.x, transformedOffset.y)
// Trigger recomposition by creating a new path object
currentPath = currentPath?.let { Path(it.asAndroidPath()) }
},
onDragEnd = {
currentPath?.let { paths.add(it) }
currentPath = null
},
)| fun inpaintImage(sourceImage: Bitmap, maskImage: Bitmap, prompt: String, editSteps: Int = 50) { | ||
| // TODO #3 - Implement ViewModel Logic for inpainting | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The inpaintImage function in the ViewModel is a stub. It should call the corresponding data source method and update the UI state with the result or an error.
fun inpaintImage(sourceImage: Bitmap, maskImage: Bitmap, prompt: String, editSteps: Int = 50) {
_uiState.value = ImagenEditingUIState.Loading
viewModelScope.launch {
try {
val bitmap = imagenDataSource.inpaintImage(sourceImage, maskImage, prompt, editSteps)
_uiState.value = ImagenEditingUIState.ImageGenerated(bitmap, contentDescription = prompt)
} catch (e: Exception) {
_uiState.value = ImagenEditingUIState.Error(e.message)
}
}
}| suspend fun outpaintImage(sourceImage: Bitmap, targetDimensions: Dimensions, prompt: String): Bitmap { | ||
| // TODO #Bonus - Implement data source for inpainting; | ||
| return sourceImage; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The outpaintImage function is a stub and the TODO comment incorrectly refers to "inpainting". While this is marked as a bonus feature, it would be good to implement it for a complete sample.
suspend fun outpaintImage(sourceImage: Bitmap, targetDimensions: Dimensions, prompt: String): Bitmap {
val imageResponse = editingModel.editImage(
prompt = prompt,
image = ImagenRawImage(sourceImage),
editingConfig = ImagenEditingConfig(
editMode = ImagenEditMode.Outpainting(targetDimensions = targetDimensions)
)
)
val image = imageResponse.images.first()
return image.asBitmap()
}| ) | ||
|
|
||
| Text( | ||
| text = "Draw a mask on the image", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The string "Draw a mask on the image" is hardcoded. It's better to extract it into a string resource for better maintainability and to support localization. Please add a new string resource in strings.xml (e.g., draw_mask_instruction) and reference it here.
| text = "Draw a mask on the image", | |
| text = stringResource(R.string.draw_mask_instruction), |
|
|
||
| buildTypes { | ||
| release { | ||
| isMinifyEnabled = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
|
||
| buildTypes { | ||
| release { | ||
| isMinifyEnabled = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| import com.android.ai.samples.imagenediting.ui.ImagenEditingScreen | ||
| import com.android.ai.theme.extendedColorScheme | ||
|
|
||
| @RequiresPermission(Manifest.permission.RECORD_AUDIO) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The RECORD_AUDIO permission is required by the sampleCatalog variable, and it's also declared in the AndroidManifest.xml. However, the Imagen Editing sample being added does not seem to use audio recording. Requesting unnecessary permissions can be a privacy concern for users. Please consider if this permission is truly needed for this sample or if it can be removed.
| val firebaseApp = FirebaseApp.getInstance() | ||
| return firebaseApp.options.projectId != "mock_project" | ||
| } catch (e: IllegalStateException) { | ||
| Log.e("CatalogScreen", "Firebase is not initialized") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tag for logging is hardcoded as "CatalogScreen". It's a better practice to define a TAG constant in a companion object for the class (or at the file level for a top-level function) and use it for logging. This improves maintainability and consistency.
| Log.e("CatalogScreen", "Firebase is not initialized") | |
| Log.e("CatalogApp", "Firebase is not initialized") |
Full Imagen Editing Sample