Thanks to visit codestin.com
Credit goes to github.com

Skip to content

🎨 A Compose multiplatform port for Androidx Palette. Generate a color palette from an image.

License

Notifications You must be signed in to change notification settings

jordond/kmpalette

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

224 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

logo


Maven Central Kotlin Build License

Compose Multiplatform badge-android badge-ios badge-desktop badge-js badge-wasm

A Compose Multiplatform library for generating color palettes from images, including the dominant color. You can use this library in combination with MaterialKolor to generate dynamic Material themes based on images.

Supports loading images from several sources, see sources.

Note: This is a port of the androidx.palette library.

Table of Contents

Platforms

This library is written for Compose Multiplatform and can be used on the following platforms:

Artifact Android Desktop iOS macOS JS WASM
kmpalette-core βœ… βœ… βœ… βœ… βœ… βœ…
extensions-base64 βœ… βœ… βœ… βœ… βœ… βœ…
extensions-network βœ… βœ… βœ… βœ… βœ… βœ…
extensions-file βœ… βœ… βœ… βœ… βœ… βœ…

Inspiration

I created this library because I wanted to use the androidx.palette library in a Compose Multiplatform app. But that library is not multiplatform, so I decided to port it.

Dynamic Material Themes

Want to create a dynamic Material theme based on the dominant color in an image?

Check out my other Compose Multiplatform library MaterialKolor!

Setup

You can add this library to your project using Gradle. There are several optional extension libraries, see sources.

Version Catalog

In libs.versions.toml:

[versions]
kmpalette = "4.0.0"

[libraries]
kmpalette-core = { module = "com.kmpalette:kmpalette-core", version.ref = "kmpalette" }
# Optional source libraries
kmpalette-extensions-base64 = { module = "com.kmpalette:extensions-base64", version.ref = "kmpalette" }
kmpalette-extensions-network = { module = "com.kmpalette:extensions-network", version.ref = "kmpalette" }
kmpalette-extensions-file = { module = "com.kmpalette:extensions-file", version.ref = "kmpalette" }

To add to a multiplatform project, add the dependency to the common source-set:

kotlin {
    sourceSets {
        commonMain {
            dependencies {
                // Core library
                implementation(libs.kmpalette.core)

                // Optional extensions based on your image source
                implementation(libs.kmpalette.extensions.base64)
                implementation(libs.kmpalette.extensions.network)
                implementation(libs.kmpalette.extensions.file)
            }
        }
    }
}

Usage

To see the generated KDocs, visit docs.kmpalette.com

To use this library, you first must have a ImageBitmap or a Painter object.

To get an ImageBitmap you can use one of the sources or by using a library that creates one for you.

Since this library is a port of the androidx.palette library, the usage is very similar. However, this library provides some helpful extension functions and composables.

Look in kmpalette-core for the main library, including extensions for the Palette and Swatch objects.

Included are two helpful @Composable-ready State objects:

  • DominantColorState - A state object that holds a generated dominant Color object.
  • PaletteState - A state object that holds a generated Palette object.

They can be used like so:

Dominant Color

You can generate a dominant color from an ImageBitmap using the rememberDominantColorState composable. This will also provide a onColor for you to use as a text color.

@Composable
fun SomeComposable(bitmap: ImageBitmap) {
    val dominantColorState = rememberDominantColorState()
    LaunchedEffect(bitmap) {
        dominantColorState.updateFrom(bitmap)
    }

    Box(
        modifier = Modifier
            .width(200.dp)
            .height(100.dp)
            .background(dominantColorState.color)
    ) {
        Text("Some Text", color = dominantColorState.onColor)
    }
}

You can also use a Painter object with the dedicated rememberPainterDominantColorState:

@Composable
fun SomeComposable(painter: Painter) {
    val dominantColorState = rememberPainterDominantColorState()
    LaunchedEffect(painter) {
        dominantColorState.updateFrom(painter)
    }

    // ...
}

Since the generation of the dominant color is an asynchronous operation that can fail, you can track the results of the operation using the DominantColorState.result object.

If you want to filter the dominant color, you can use the pass a lambda to rememberDominantColorState():

val dominantColorState = rememberDominantColorState(
    isSwatchValid = { swatch ->
        swatch.color.contrastAgainst(MaterialTheme.colorScheme.surfaceColor) >= MinContrastRatio
    }
)
LaunchedEffect(bitmap) {
    dominantColorState.updateFrom(bitmap)
}

Generate a color Palette

If you want a whole color palette instead of just a dominant color, you can use the rememberPaletteState composable. This will provide a Palette object which contains a few different color Swatchs, each has their own color and onColor.

Using an ImageBitmap:

@Composable
fun SomeComposable(bitmap: ImageBitmap) {
    val paletteState = rememberPaletteState()
    LaunchedEffect(bitmap) {
        paletteState.generate(bitmap)
    }

    Box(
        modifier = Modifier
            .width(200.dp)
            .height(100.dp)
            .background(paletteState.vibrantSwatch?.color ?: Color.White)
    ) {
        Text(
            text = "Some Text",
            color = paletteState.vibrantSwatch?.onColor ?: LocalContentColor.current,
        )
    }
}

Or using a Painter:

@Composable
fun SomeComposable(painter: Painter) {
    val paletteState = rememberPainterPaletteState()
    LaunchedEffect(painter) {
        paletteState.generate(painter)
    }

    // ...
}

Since the generation of the palette is an asynchronous operation that can fail, you can track the results of the operation using the PaletteState.state object.

Sources

The kmpalette-core library provides the core functionality for generating color palettes from a ImageBitmap or a Painter object.

This library provides some extension artifacts for popular sources.

Artifact Library Loader Input Class
extensions-base64 N/A Base64Loader String
extensions-network Ktor NetworkLoader Url
extensions-file FileKit PlatformFileLoader PlatformFile

Each of these extensions provides dedicated composable functions. For example, the extensions-network module provides rememberNetworkDominantColorState and rememberNetworkPaletteState:

@Composable
fun SomeComposable(url: Url) {
    val dominantColorState = rememberNetworkDominantColorState(
        defaultColor = MaterialTheme.colorScheme.primary,
        defaultOnColor = MaterialTheme.colorScheme.onPrimary,
    )
    LaunchedEffect(url) {
        dominantColorState.updateFrom(url)
    }

    Box(
        modifier = Modifier
            .width(200.dp)
            .height(100.dp)
            .background(dominantColorState.color)
    ) {
        Text("Some Text", color = dominantColorState.onColor)
    }
}

Compose Multiplatform Resources

To generate a palette from a DrawableResource you can use the rememberResourceDominantColorState or rememberResourcePaletteState composables which work directly with Compose Multiplatform resources:

@Composable
fun MyComposable() {
    val dominantColorState = rememberResourceDominantColorState()
    LaunchedEffect(Unit) {
        dominantColorState.updateFrom(Res.drawable.my_image)
    }
}

Alternatively, you can use the @Composable imageResource() to get an ImageBitmap then pass that to the default loader:

@Composable
fun MyComposable() {
    val image = imageResource(Res.drawable.my_image)
    val dominantColorState = rememberDominantColorState()
    LaunchedEffect(image) {
        dominantColorState.updateFrom(image)
    }
}

Migration

If you are migrating from version 3.x, please see the Migration Guide for detailed instructions on updating your code.

Key changes in 4.0:

  • extensions-bytearray module has been removed
  • extensions-file now uses FileKit instead of Okio
  • New dedicated composable functions for each loader type

Feature Requests

If you have a feature request, please open an issue. If you would like to implement a feature request, refer to the Contributing section.

Contributing

Contributions are always welcome!. If you'd like to contribute, please feel free to create a PR or open an issue.

License

The module androidx-palette is licensed under the Apache License, Version 2.0. See their LICENSE and their repository here for more information.

Changes from the original source

  • Convert Java code to Kotlin
  • Convert library to Kotlin Multiplatform

For the remaining code see LICENSE for more information.

Contributors 4

  •  
  •  
  •  
  •  

Languages