Skip to content

Conversation

@madebymozart
Copy link
Contributor

Full Imagen Editing Sample

@SigmanZero SigmanZero merged commit 1122264 into main Oct 28, 2025
1 of 2 checks passed
@gemini-code-assist
Copy link

Summary of Changes

Hello @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

  • New Imagen Editing Sample: Introduces a complete Imagen editing sample application, allowing users to generate images from text prompts and then perform inpainting edits on specific areas of the generated images.
  • Firebase Imagen API Integration: The sample leverages the Firebase Imagen API for both initial image generation and subsequent inpainting operations, showcasing its capabilities within an Android application.
  • Interactive Mask Editor UI: A new Compose UI component, ImagenEditingMaskEditor, is added to enable users to draw masks directly on generated images, defining the areas for inpainting.
  • Modular Project Structure: The new sample is integrated into a modular project structure, including a dedicated application module (Imagen Editing/app), the sample-specific module (Imagen Editing/samples/imagen-editing), and a shared UI component library (Imagen Editing/ui-component).
  • Gradle and Dependency Setup: Comprehensive Gradle configurations are added for the new modules, including Kotlin, Compose, Hilt, Firebase AI, and various AndroidX dependencies, ensuring a modern Android development setup.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a 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.

Comment on lines +110 to +113
suspend fun inpaintImage(sourceImage: Bitmap, maskImage: Bitmap, prompt: String, editSteps: Int = DEFAULT_EDIT_STEPS): Bitmap {
// TODO #1 - Implement data source for inpainting;
return sourceImage;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

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()
    }

Comment on lines +82 to +90
detectDragGestures(
// TODO #2 - Implement Drag logic
onDragStart = { startOffset ->
},
onDrag = { change, _ ->
},
onDragEnd = {
},
)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

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
                            },
                        )

Comment on lines +56 to +58
fun inpaintImage(sourceImage: Bitmap, maskImage: Bitmap, prompt: String, editSteps: Int = 50) {
// TODO #3 - Implement ViewModel Logic for inpainting
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

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)
            }
        }
    }

Comment on lines +126 to +129
suspend fun outpaintImage(sourceImage: Bitmap, targetDimensions: Dimensions, prompt: String): Bitmap {
// TODO #Bonus - Implement data source for inpainting;
return sourceImage;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

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",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
text = "Draw a mask on the image",
text = stringResource(R.string.draw_mask_instruction),


buildTypes {
release {
isMinifyEnabled = false

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Minification is disabled for release builds. For a sample app that is meant to showcase best practices, it's recommended to enable minification for release builds to reduce the app size.

            isMinifyEnabled = true


buildTypes {
release {
isMinifyEnabled = false

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Minification is disabled for release builds. It's a good practice to enable minification for release builds to reduce the library size, even in a sample project.

            isMinifyEnabled = true

import com.android.ai.samples.imagenediting.ui.ImagenEditingScreen
import com.android.ai.theme.extendedColorScheme

@RequiresPermission(Manifest.permission.RECORD_AUDIO)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
Log.e("CatalogScreen", "Firebase is not initialized")
Log.e("CatalogApp", "Firebase is not initialized")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants