diff --git a/Imagen Editing/.kotlin/sessions/kotlin-compiler-10635189820473949239.salive b/Imagen Editing/.kotlin/sessions/kotlin-compiler-10635189820473949239.salive new file mode 100644 index 0000000..e69de29 diff --git a/Imagen Editing/app/build.gradle.kts b/Imagen Editing/app/build.gradle.kts index 6423e72..1aaea2f 100644 --- a/Imagen Editing/app/build.gradle.kts +++ b/Imagen Editing/app/build.gradle.kts @@ -24,11 +24,11 @@ plugins { } android { - namespace = "com.android.ai.catalog" + namespace = "com.android.ai.samples.imagenediting" compileSdk = 36 defaultConfig { - applicationId = "com.android.ai.catalog" + applicationId = "com.android.ai.samples.imagenediting" minSdk = 26 targetSdk = 36 versionCode = 1 diff --git a/Imagen Editing/app/src/main/java/com/android/ai/catalog/CatalogApplication.kt b/Imagen Editing/app/src/main/java/com/android/ai/samples/imagenediting/CatalogApplication.kt similarity index 94% rename from Imagen Editing/app/src/main/java/com/android/ai/catalog/CatalogApplication.kt rename to Imagen Editing/app/src/main/java/com/android/ai/samples/imagenediting/CatalogApplication.kt index 6c1681f..23564d5 100644 --- a/Imagen Editing/app/src/main/java/com/android/ai/catalog/CatalogApplication.kt +++ b/Imagen Editing/app/src/main/java/com/android/ai/samples/imagenediting/CatalogApplication.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.ai.catalog +package com.android.ai.samples.imagenediting import android.app.Application import dagger.hilt.android.HiltAndroidApp diff --git a/Imagen Editing/app/src/main/java/com/android/ai/catalog/MainActivity.kt b/Imagen Editing/app/src/main/java/com/android/ai/samples/imagenediting/MainActivity.kt similarity index 92% rename from Imagen Editing/app/src/main/java/com/android/ai/catalog/MainActivity.kt rename to Imagen Editing/app/src/main/java/com/android/ai/samples/imagenediting/MainActivity.kt index ad61c64..81032f5 100644 --- a/Imagen Editing/app/src/main/java/com/android/ai/catalog/MainActivity.kt +++ b/Imagen Editing/app/src/main/java/com/android/ai/samples/imagenediting/MainActivity.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.ai.catalog +package com.android.ai.samples.imagenediting import android.os.Bundle import androidx.activity.ComponentActivity @@ -21,7 +21,7 @@ import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.ui.Modifier -import com.android.ai.catalog.ui.CatalogApp +import com.android.ai.samples.imagenediting.ui.CatalogApp import com.android.ai.theme.AISampleCatalogTheme import dagger.hilt.android.AndroidEntryPoint diff --git a/Imagen Editing/app/src/main/java/com/android/ai/catalog/domain/SampleCatalog.kt b/Imagen Editing/app/src/main/java/com/android/ai/samples/imagenediting/domain/SampleCatalog.kt similarity index 92% rename from Imagen Editing/app/src/main/java/com/android/ai/catalog/domain/SampleCatalog.kt rename to Imagen Editing/app/src/main/java/com/android/ai/samples/imagenediting/domain/SampleCatalog.kt index 9a7b605..4083d2e 100644 --- a/Imagen Editing/app/src/main/java/com/android/ai/catalog/domain/SampleCatalog.kt +++ b/Imagen Editing/app/src/main/java/com/android/ai/samples/imagenediting/domain/SampleCatalog.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.ai.catalog.domain +package com.android.ai.samples.imagenediting.domain import android.Manifest import androidx.annotation.DrawableRes @@ -21,8 +21,8 @@ import androidx.annotation.RequiresPermission import androidx.annotation.StringRes import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color -import com.android.ai.catalog.R -import com.android.ai.samples.imagenediting.ui.ImagenEditingScreen +import com.android.ai.samples.imagenediting.R +import com.android.ai.samples.imagenediting.sample.ui.ImagenEditingScreen import com.android.ai.theme.extendedColorScheme @RequiresPermission(Manifest.permission.RECORD_AUDIO) diff --git a/Imagen Editing/app/src/main/java/com/android/ai/catalog/ui/CatalogApp.kt b/Imagen Editing/app/src/main/java/com/android/ai/samples/imagenediting/ui/CatalogApp.kt similarity index 98% rename from Imagen Editing/app/src/main/java/com/android/ai/catalog/ui/CatalogApp.kt rename to Imagen Editing/app/src/main/java/com/android/ai/samples/imagenediting/ui/CatalogApp.kt index 813d638..2428e76 100644 --- a/Imagen Editing/app/src/main/java/com/android/ai/catalog/ui/CatalogApp.kt +++ b/Imagen Editing/app/src/main/java/com/android/ai/samples/imagenediting/ui/CatalogApp.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.ai.catalog.ui +package com.android.ai.samples.imagenediting.ui import android.content.Intent import android.util.Log @@ -58,8 +58,8 @@ import androidx.core.net.toUri import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController -import com.android.ai.catalog.R -import com.android.ai.catalog.domain.sampleCatalog +import com.android.ai.samples.imagenediting.R +import com.android.ai.samples.imagenediting.domain.sampleCatalog import com.google.firebase.FirebaseApp import kotlinx.serialization.Serializable diff --git a/Imagen Editing/app/src/main/java/com/android/ai/catalog/ui/CatalogRowCard.kt b/Imagen Editing/app/src/main/java/com/android/ai/samples/imagenediting/ui/CatalogRowCard.kt similarity index 94% rename from Imagen Editing/app/src/main/java/com/android/ai/catalog/ui/CatalogRowCard.kt rename to Imagen Editing/app/src/main/java/com/android/ai/samples/imagenediting/ui/CatalogRowCard.kt index f607a0e..35c9ec9 100644 --- a/Imagen Editing/app/src/main/java/com/android/ai/catalog/ui/CatalogRowCard.kt +++ b/Imagen Editing/app/src/main/java/com/android/ai/samples/imagenediting/ui/CatalogRowCard.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.ai.catalog.ui +package com.android.ai.samples.imagenediting.ui import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Column @@ -37,9 +37,9 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.android.ai.catalog.R -import com.android.ai.catalog.domain.SampleCatalogItem -import com.android.ai.catalog.domain.SampleTags +import com.android.ai.samples.imagenediting.R +import com.android.ai.samples.imagenediting.domain.SampleCatalogItem +import com.android.ai.samples.imagenediting.domain.SampleTags import com.android.ai.theme.AISampleCatalogTheme import com.android.ai.uicomponent.Tag diff --git a/Imagen Editing/app/src/main/java/com/android/ai/catalog/ui/CatalogWideCard.kt b/Imagen Editing/app/src/main/java/com/android/ai/samples/imagenediting/ui/CatalogWideCard.kt similarity index 94% rename from Imagen Editing/app/src/main/java/com/android/ai/catalog/ui/CatalogWideCard.kt rename to Imagen Editing/app/src/main/java/com/android/ai/samples/imagenediting/ui/CatalogWideCard.kt index 81c1f10..37f892c 100644 --- a/Imagen Editing/app/src/main/java/com/android/ai/catalog/ui/CatalogWideCard.kt +++ b/Imagen Editing/app/src/main/java/com/android/ai/samples/imagenediting/ui/CatalogWideCard.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.ai.catalog.ui +package com.android.ai.samples.imagenediting.ui import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Column @@ -33,9 +33,9 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.android.ai.catalog.R -import com.android.ai.catalog.domain.SampleCatalogItem -import com.android.ai.catalog.domain.SampleTags +import com.android.ai.samples.imagenediting.R +import com.android.ai.samples.imagenediting.domain.SampleCatalogItem +import com.android.ai.samples.imagenediting.domain.SampleTags import com.android.ai.theme.AISampleCatalogTheme import com.android.ai.uicomponent.Tag diff --git a/Imagen Editing/samples/imagen-editing/build.gradle.kts b/Imagen Editing/samples/imagen-editing/build.gradle.kts index bf26d7b..441692e 100644 --- a/Imagen Editing/samples/imagen-editing/build.gradle.kts +++ b/Imagen Editing/samples/imagen-editing/build.gradle.kts @@ -21,7 +21,7 @@ plugins { } android { - namespace = "com.android.ai.samples.imagenediting" + namespace = "com.android.ai.samples.imagenediting.sample" compileSdk = 36 buildFeatures { diff --git a/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/data/ImagenEditingDataSource.kt b/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/sample/data/ImagenEditingDataSource.kt similarity index 73% rename from Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/data/ImagenEditingDataSource.kt rename to Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/sample/data/ImagenEditingDataSource.kt index a846f1f..b8918ad 100644 --- a/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/data/ImagenEditingDataSource.kt +++ b/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/sample/data/ImagenEditingDataSource.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.ai.samples.imagenediting.data +package com.android.ai.samples.imagenediting.sample.data import android.graphics.Bitmap import com.google.firebase.Firebase @@ -46,18 +46,33 @@ import javax.inject.Singleton @Singleton class ImagenEditingDataSource @Inject constructor() { private companion object { - // TODO #1 - Define constants for Imagen model names and default values. - const val IMAGEN_MODEL_NAME = "" - const val IMAGEN_EDITING_MODEL_NAME = "" + const val IMAGEN_MODEL_NAME = "imagen-4.0-ultra-generate-001" + const val IMAGEN_EDITING_MODEL_NAME = "imagen-3.0-capability-001" const val DEFAULT_EDIT_STEPS = 50 + const val DEFAULT_STYLE_STRENGTH = 1 } - // TODO #2 - Implement Firebase calls using Imagen models - // @OptIn(PublicPreviewAPI::class) - // private val imagenModel = + @OptIn(PublicPreviewAPI::class) + private val imagenModel = + Firebase.ai(backend = GenerativeBackend.vertexAI()).imagenModel( + IMAGEN_MODEL_NAME, + generationConfig = ImagenGenerationConfig( + numberOfImages = 1, + aspectRatio = ImagenAspectRatio.SQUARE_1x1, + imageFormat = ImagenImageFormat.jpeg(compressionQuality = 75), + ), + ) - // @OptIn(PublicPreviewAPI::class) - // private val editingModel = + @OptIn(PublicPreviewAPI::class) + private val editingModel = + Firebase.ai(backend = GenerativeBackend.vertexAI()).imagenModel( + IMAGEN_EDITING_MODEL_NAME, + generationConfig = ImagenGenerationConfig( + numberOfImages = 1, + aspectRatio = ImagenAspectRatio.SQUARE_1x1, + imageFormat = ImagenImageFormat.jpeg(compressionQuality = 75), + ), + ) /** * Generates an image based on the provided prompt. @@ -93,8 +108,18 @@ class ImagenEditingDataSource @Inject constructor() { */ @OptIn(PublicPreviewAPI::class) suspend fun inpaintImage(sourceImage: Bitmap, maskImage: Bitmap, prompt: String, editSteps: Int = DEFAULT_EDIT_STEPS): Bitmap { - // TODO #3 - Implement data source for inpainting; - return sourceImage; + val imageResponse = editingModel.editImage( + referenceImages = listOf( + ImagenRawImage(sourceImage.toImagenInlineImage()), + ImagenRawMask(maskImage.toImagenInlineImage()), + ), + prompt = prompt, + config = ImagenEditingConfig( + editMode = ImagenEditMode.INPAINT_INSERTION, + editSteps = editSteps, + ), + ) + return imageResponse.images.first().asBitmap() } /** diff --git a/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/ui/ImagenEditingMaskEditor.kt b/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/sample/ui/ImagenEditingMaskEditor.kt similarity index 87% rename from Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/ui/ImagenEditingMaskEditor.kt rename to Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/sample/ui/ImagenEditingMaskEditor.kt index cb562c5..38f4a79 100644 --- a/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/ui/ImagenEditingMaskEditor.kt +++ b/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/sample/ui/ImagenEditingMaskEditor.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.ai.samples.imagenediting.ui +package com.android.ai.samples.imagenediting.sample.ui import android.graphics.Bitmap import android.graphics.Paint @@ -58,7 +58,7 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.core.graphics.createBitmap -import com.android.ai.samples.imagenediting.R +import com.android.ai.samples.imagenediting.sample.R import kotlin.math.min @Composable @@ -80,12 +80,27 @@ fun ImagenEditingMaskEditor(sourceBitmap: Bitmap, onMaskFinalized: (Bitmap) -> U .fillMaxWidth() .pointerInput(Unit) { detectDragGestures( - // TODO #4 - Implement Drag logic onDragStart = { startOffset -> + val transformedStart = Offset( + (startOffset.x - offsetX) / scale, + (startOffset.y - offsetY) / scale, + ) + currentPath = Path().apply { moveTo(transformedStart.x, transformedStart.y) } }, onDrag = { change, _ -> + currentPath?.let { + val transformedChange = Offset( + (change.position.x - offsetX) / scale, + (change.position.y - offsetY) / scale, + ) + it.lineTo(transformedChange.x, transformedChange.y) + currentPath = Path().apply { addPath(it) } + } + change.consume() }, onDragEnd = { + currentPath?.let { paths.add(it) } + currentPath = null }, ) }, diff --git a/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/ui/ImagenEditingScreen.kt b/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/sample/ui/ImagenEditingScreen.kt similarity index 99% rename from Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/ui/ImagenEditingScreen.kt rename to Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/sample/ui/ImagenEditingScreen.kt index e7c76cb..87a704e 100644 --- a/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/ui/ImagenEditingScreen.kt +++ b/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/sample/ui/ImagenEditingScreen.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.ai.samples.imagenediting.ui +package com.android.ai.samples.imagenediting.sample.ui import android.graphics.Bitmap import android.graphics.BitmapFactory @@ -62,7 +62,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.android.ai.samples.imagenediting.R +import com.android.ai.samples.imagenediting.sample.R import com.android.ai.uicomponent.GenerateButton import com.android.ai.uicomponent.SampleDetailTopAppBar import com.android.ai.uicomponent.TextInput diff --git a/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/ui/ImagenEditingUIState.kt b/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/sample/ui/ImagenEditingUIState.kt similarity index 95% rename from Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/ui/ImagenEditingUIState.kt rename to Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/sample/ui/ImagenEditingUIState.kt index 0a37a73..0b65ee6 100644 --- a/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/ui/ImagenEditingUIState.kt +++ b/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/sample/ui/ImagenEditingUIState.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.ai.samples.imagenediting.ui +package com.android.ai.samples.imagenediting.sample.ui import android.graphics.Bitmap diff --git a/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/ui/ImagenEditingViewModel.kt b/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/sample/ui/ImagenEditingViewModel.kt similarity index 76% rename from Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/ui/ImagenEditingViewModel.kt rename to Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/sample/ui/ImagenEditingViewModel.kt index 9dfaa86..754188a 100644 --- a/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/ui/ImagenEditingViewModel.kt +++ b/Imagen Editing/samples/imagen-editing/src/main/java/com/android/ai/samples/imagenediting/sample/ui/ImagenEditingViewModel.kt @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.ai.samples.imagenediting.ui +package com.android.ai.samples.imagenediting.sample.ui import android.graphics.Bitmap import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.android.ai.samples.imagenediting.data.ImagenEditingDataSource +import com.android.ai.samples.imagenediting.sample.data.ImagenEditingDataSource import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow @@ -54,8 +54,23 @@ class ImagenEditingViewModel @Inject constructor(private val imagenDataSource: I } fun inpaintImage(sourceImage: Bitmap, maskImage: Bitmap, prompt: String, editSteps: Int = 50) { - // TODO #5 - Implement ViewModel Logic for inpainting - } + _uiState.value = ImagenEditingUIState.Loading + viewModelScope.launch { + try { + val inpaintedBitmap = imagenDataSource.inpaintImage( + sourceImage = sourceImage, + maskImage = maskImage, + prompt = prompt, + editSteps = editSteps, + ) + _uiState.value = ImagenEditingUIState.ImageGenerated( + bitmap = inpaintedBitmap, + contentDescription = "Inpainted image based on prompt: $prompt", + ) + } catch (e: Exception) { + _uiState.value = ImagenEditingUIState.Error(e.localizedMessage ?: "An unknown error occurred during inpainting") + } + } } fun onImageMaskReady(originalBitmap: Bitmap, maskBitmap: Bitmap) { val originalContentDescription = (_uiState.value as? ImagenEditingUIState.ImageGenerated)?.contentDescription ?: "Edited image"