From b4f13c66e70e354939deabd010429c5af5271abd Mon Sep 17 00:00:00 2001 From: DatLag Date: Sat, 9 Dec 2023 15:33:22 +0100 Subject: [PATCH 1/4] feat(Loader): New PainterLoader provide possibility to use any Painter for loading a Palette --- .../kotlin/com/kmpalette/PaletteState.kt | 32 +++++++++++++++ .../com/kmpalette/internal/PainterImage.kt | 40 +++++++++++++++++++ .../kotlin/com/kmpalette/loader/Loader.kt | 17 ++++++++ 3 files changed, 89 insertions(+) create mode 100644 kmpalette-core/src/commonMain/kotlin/com/kmpalette/internal/PainterImage.kt diff --git a/kmpalette-core/src/commonMain/kotlin/com/kmpalette/PaletteState.kt b/kmpalette-core/src/commonMain/kotlin/com/kmpalette/PaletteState.kt index a58e2bf..3b0758b 100644 --- a/kmpalette-core/src/commonMain/kotlin/com/kmpalette/PaletteState.kt +++ b/kmpalette-core/src/commonMain/kotlin/com/kmpalette/PaletteState.kt @@ -7,9 +7,15 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.LayoutDirection import androidx.palette.graphics.Palette import com.kmpalette.internal.LruCache import com.kmpalette.loader.ImageBitmapLoader +import com.kmpalette.loader.PainterLoader import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers import kotlin.coroutines.CoroutineContext @@ -60,6 +66,32 @@ public fun rememberPaletteState( } } +/** + * Wrapper around [rememberPaletteState] that uses [PainterLoader] to load the image. + * + * @see rememberPaletteState + * @param[density] The [Density] used for drawing the [Painter] as [ImageBitmap]. + * @param[layoutDirection] The [LayoutDirection] used for drawing the [Painter] as [ImageBitmap]. + * @param[cacheSize] The maximum number of [Palette]s to cache. If 0, no caching will be done. + * @param[coroutineContext] The [CoroutineContext] to use for generating [Palette]s. + * @param[builder] A lambda that will be applied to the [Palette.Builder] to customize the + * generation of the [Palette]. + * @return A [PaletteState] that will be remembered across composition. + */ +@Composable +public fun rememberPainterPaletteState( + density: Density = LocalDensity.current, + layoutDirection: LayoutDirection = LocalLayoutDirection.current, + cacheSize: Int = DominantColorState.DEFAULT_CACHE_SIZE, + coroutineContext: CoroutineContext = Dispatchers.Default, + builder: Palette.Builder.() -> Unit = {}, +): PaletteState = rememberPaletteState( + loader = PainterLoader(density, layoutDirection), + cacheSize = cacheSize, + coroutineContext = coroutineContext, + builder = builder +) + /** * A state object that generates a [Palette] from an [ImageBitmap] using [loader]. * diff --git a/kmpalette-core/src/commonMain/kotlin/com/kmpalette/internal/PainterImage.kt b/kmpalette-core/src/commonMain/kotlin/com/kmpalette/internal/PainterImage.kt new file mode 100644 index 0000000..8ba7468 --- /dev/null +++ b/kmpalette-core/src/commonMain/kotlin/com/kmpalette/internal/PainterImage.kt @@ -0,0 +1,40 @@ +package com.kmpalette.internal + +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Canvas +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.drawscope.CanvasDrawScope +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.LayoutDirection +import kotlin.math.roundToInt + +internal class PainterImage( + private val painter: Painter, + private val density: Density, + private val layoutDirection: LayoutDirection +) { + fun asBitmap( + width: Int = painter.intrinsicSize.width.roundToInt(), + height: Int = painter.intrinsicSize.height.roundToInt() + ): ImageBitmap { + val bitmap = ImageBitmap(width, height) + val canvas = Canvas(bitmap) + val floatSize = Size(width.toFloat(), height.toFloat()) + + bitmap.prepareToDraw() + + CanvasDrawScope().draw( + density = density, + layoutDirection = layoutDirection, + canvas = canvas, + size = floatSize + ) { + with(painter) { + draw(floatSize) + } + } + + return bitmap + } +} \ No newline at end of file diff --git a/kmpalette-core/src/commonMain/kotlin/com/kmpalette/loader/Loader.kt b/kmpalette-core/src/commonMain/kotlin/com/kmpalette/loader/Loader.kt index f21a50c..98d97c2 100644 --- a/kmpalette-core/src/commonMain/kotlin/com/kmpalette/loader/Loader.kt +++ b/kmpalette-core/src/commonMain/kotlin/com/kmpalette/loader/Loader.kt @@ -1,6 +1,11 @@ package com.kmpalette.loader import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.painter.BitmapPainter +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.LayoutDirection +import com.kmpalette.internal.PainterImage /** * A default loader that takes an [ImageBitmap] and returns it. @@ -8,4 +13,16 @@ import androidx.compose.ui.graphics.ImageBitmap internal val ImageBitmapLoader = object : ImageBitmapLoader { override suspend fun load(input: ImageBitmap): ImageBitmap = input +} + +/** + * A default loader that takes an [Painter], draws it as an [ImageBitmap] and returns that. + */ +public class PainterLoader( + private val density: Density, + private val layoutDirection: LayoutDirection +) : ImageBitmapLoader { + override suspend fun load(input: Painter): ImageBitmap { + return PainterImage(input, density, layoutDirection).asBitmap() + } } \ No newline at end of file From e612c96b3a78c040721d109e1c8f6a90dc1cc763 Mon Sep 17 00:00:00 2001 From: DatLag Date: Sat, 9 Dec 2023 17:05:28 +0100 Subject: [PATCH 2/4] added rememberPainterDominantColorState --- .../com/kmpalette/DominantColorState.kt | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/kmpalette-core/src/commonMain/kotlin/com/kmpalette/DominantColorState.kt b/kmpalette-core/src/commonMain/kotlin/com/kmpalette/DominantColorState.kt index 907b31d..7430833 100644 --- a/kmpalette-core/src/commonMain/kotlin/com/kmpalette/DominantColorState.kt +++ b/kmpalette-core/src/commonMain/kotlin/com/kmpalette/DominantColorState.kt @@ -10,9 +10,15 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.LayoutDirection import androidx.palette.graphics.Palette import com.kmpalette.internal.LruCache import com.kmpalette.loader.ImageBitmapLoader +import com.kmpalette.loader.PainterLoader import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers import kotlin.coroutines.CoroutineContext @@ -61,6 +67,41 @@ public fun rememberDominantColorState( builder = builder, ) +/** + * Wrapper around [rememberDominantColorState] that uses [PainterLoader] to load the image. + * + * @see rememberDominantColorState + * @param[defaultColor] The default color, which will be used if [Palette.generate] fails. + * @param[defaultOnColor] The default color to use _on_ [defaultColor]. + * @param[density] The [Density] used for drawing the [Painter] as [ImageBitmap]. + * @param[layoutDirection] The [LayoutDirection] used for drawing the [Painter] as [ImageBitmap]. + * @param[cacheSize] The size of the LruCache used to store recent results. Pass `0` to disable. + * @param[coroutineContext] The [CoroutineContext] used to launch the coroutine. + * @param[isSwatchValid] A lambda which allows filtering of the calculated [Palette.Swatch]. + * @param[builder] A lambda which allows filtering of the calculated [Palette.Builder] used to generate + * the [Palette]. + * @return A [DominantColorState] which can be used to generate a dominant color from a [Painter]. + */ +@Composable +public fun rememberPainterDominantColorState( + defaultColor: Color = MaterialTheme.colorScheme.primary, + defaultOnColor: Color = MaterialTheme.colorScheme.onPrimary, + density: Density = LocalDensity.current, + layoutDirection: LayoutDirection = LocalLayoutDirection.current, + cacheSize: Int = 0, + coroutineContext: CoroutineContext = Dispatchers.Default, + isSwatchValid: (Palette.Swatch) -> Boolean = { true }, + builder: Palette.Builder.() -> Unit = {}, +): DominantColorState = rememberDominantColorState( + loader = PainterLoader(density, layoutDirection), + defaultColor = defaultColor, + defaultOnColor = defaultOnColor, + cacheSize = cacheSize, + coroutineContext = coroutineContext, + isSwatchValid = isSwatchValid, + builder = builder +) + /** * Create a [DominantColorState] which will be remembered across compositions. Then can be used * to generate a dominant color from an [ImageBitmap]. From 2e05658af4903e1c7352cc78fcfd739d0e6d3310 Mon Sep 17 00:00:00 2001 From: DatLag Date: Sun, 10 Dec 2023 15:04:39 +0100 Subject: [PATCH 3/4] API Dump --- gradle/libs.versions.toml | 2 +- kmpalette-core/api/android/kmpalette-core.api | 9 +++++++++ kmpalette-core/api/jvm/kmpalette-core.api | 9 +++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 72f91e3..a880e51 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ sdk-target = "34" sdk-compile = "34" sdk-min = "21" -agp = "8.2.0" +agp = "8.1.4" kotlin = "1.9.21" ktor = "2.3.7" versions = "0.50.0" diff --git a/kmpalette-core/api/android/kmpalette-core.api b/kmpalette-core/api/android/kmpalette-core.api index 8174599..df6bbfc 100644 --- a/kmpalette-core/api/android/kmpalette-core.api +++ b/kmpalette-core/api/android/kmpalette-core.api @@ -18,6 +18,7 @@ public final class com/kmpalette/DominantColorState$Companion { public final class com/kmpalette/DominantColorStateKt { public static final fun rememberDominantColorState-1Kfb2uI (JJILkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Lcom/kmpalette/DominantColorState; public static final fun rememberDominantColorState-K2djEUw (Lcom/kmpalette/loader/ImageBitmapLoader;JJILkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Lcom/kmpalette/DominantColorState; + public static final fun rememberPainterDominantColorState-n5X53cU (JJLandroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;ILkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Lcom/kmpalette/DominantColorState; } public final class com/kmpalette/PaletteKt { @@ -88,6 +89,7 @@ public final class com/kmpalette/PaletteState$Companion { } public final class com/kmpalette/PaletteStateKt { + public static final fun rememberPainterPaletteState (Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;ILkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Lcom/kmpalette/PaletteState; public static final fun rememberPaletteState (ILkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Lcom/kmpalette/PaletteState; public static final fun rememberPaletteState (Lcom/kmpalette/loader/ImageBitmapLoader;ILkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Lcom/kmpalette/PaletteState; } @@ -153,3 +155,10 @@ public final class com/kmpalette/SwatchTarget$VibrantLight : com/kmpalette/Swatc public fun toString ()Ljava/lang/String; } +public final class com/kmpalette/loader/PainterLoader : com/kmpalette/loader/ImageBitmapLoader { + public static final field $stable I + public fun (Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;)V + public fun load (Landroidx/compose/ui/graphics/painter/Painter;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public synthetic fun load (Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + diff --git a/kmpalette-core/api/jvm/kmpalette-core.api b/kmpalette-core/api/jvm/kmpalette-core.api index 8174599..df6bbfc 100644 --- a/kmpalette-core/api/jvm/kmpalette-core.api +++ b/kmpalette-core/api/jvm/kmpalette-core.api @@ -18,6 +18,7 @@ public final class com/kmpalette/DominantColorState$Companion { public final class com/kmpalette/DominantColorStateKt { public static final fun rememberDominantColorState-1Kfb2uI (JJILkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Lcom/kmpalette/DominantColorState; public static final fun rememberDominantColorState-K2djEUw (Lcom/kmpalette/loader/ImageBitmapLoader;JJILkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Lcom/kmpalette/DominantColorState; + public static final fun rememberPainterDominantColorState-n5X53cU (JJLandroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;ILkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Lcom/kmpalette/DominantColorState; } public final class com/kmpalette/PaletteKt { @@ -88,6 +89,7 @@ public final class com/kmpalette/PaletteState$Companion { } public final class com/kmpalette/PaletteStateKt { + public static final fun rememberPainterPaletteState (Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;ILkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Lcom/kmpalette/PaletteState; public static final fun rememberPaletteState (ILkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Lcom/kmpalette/PaletteState; public static final fun rememberPaletteState (Lcom/kmpalette/loader/ImageBitmapLoader;ILkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Lcom/kmpalette/PaletteState; } @@ -153,3 +155,10 @@ public final class com/kmpalette/SwatchTarget$VibrantLight : com/kmpalette/Swatc public fun toString ()Ljava/lang/String; } +public final class com/kmpalette/loader/PainterLoader : com/kmpalette/loader/ImageBitmapLoader { + public static final field $stable I + public fun (Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;)V + public fun load (Landroidx/compose/ui/graphics/painter/Painter;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public synthetic fun load (Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + From 75c2de47b2bb8c9846ead231b0506b6a805312f5 Mon Sep 17 00:00:00 2001 From: DatLag <46448715+DatL4g@users.noreply.github.com> Date: Sun, 10 Dec 2023 15:05:10 +0100 Subject: [PATCH 4/4] Discard changes to gradle/libs.versions.toml --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a880e51..72f91e3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ sdk-target = "34" sdk-compile = "34" sdk-min = "21" -agp = "8.1.4" +agp = "8.2.0" kotlin = "1.9.21" ktor = "2.3.7" versions = "0.50.0"