# colorpicker-compose: tapping a pixel to read its color in Compose and Kotlin Multiplatform

> colorpicker-compose is a Kotlin Multiplatform library that reads a color from an arbitrary image by tapping it, with alpha, brightness, hue and saturation sliders on top. The interesting detail is what happens when the tap lands on a band beside the image or on a transparent pixel.

**skydoves/colorpicker-compose** — 🎨 Kotlin Multiplatform color picker library for getting colors from any images by tapping on the desired color.

- Repository: https://github.com/skydoves/colorpicker-compose
- Website: https://skydoves.github.io/colorpicker-compose/
- Stars: 762 · Forks: 66
- Language: Kotlin
- License: Apache-2.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/skydoves-colorpicker-compose

## Picking a color by tapping a photo rather than dragging a hue wheel

colorpicker-compose is a Kotlin Multiplatform library for getting colors out of any image, gallery pictures included, by tapping the color you want. The description in the README is precise about the scope: instead of a swatch grid, the user works with the image itself. That design changes the interaction. On a palette screen you are choosing among colors someone else chose for you; on a photograph you are pointing at a thing in the frame and asking the app what it actually is. The library also ships alpha, brightness, hue and saturation sliders that run horizontally or vertically to adjust ARGB and HSV factors, plus gesture lifecycle callbacks for fine-grained interaction handling. The licence is Apache-2.0, the minimum API level is 21, and the artifact is published on Maven Central under com.github.skydoves:colorpicker-compose.

## One controller, and two picker composables that share it

The architecture is straightforward and worth understanding because it determines how you wire things up. You start by initializing a ColorPickerController, which the README describes as the object that allows you to control color pickers and all subcomponents.

```kotlin
val controller = rememberColorPickerController()
```

There are then two main composables. ImageColorPicker works against a bitmap you supply, for example a drawable resource.

```kotlin
ImageColorPicker(
    modifier = Modifier.fillMaxSize(),
    paletteImageBitmap = ImageBitmap.imageResource(R.drawable.palettebar),
    controller = controller
)
```

HsvColorPicker works against an HSV palette it draws itself, and takes an initialColor argument to start from a specific color, with white as the default. The distinction matters for configuration. The README notes that HsvColorPicker draws its own palette, so setPaletteImageBitmap on the controller and the paletteContentScale parameter apply to ImageColorPicker only. Both pickers report through an onColorChanged callback that receives a ColorEnvelope, and HsvColorPicker additionally exposes onStart and onFinish, which fire when the user touches the picker and when the finger lifts.

## FIT and CROP decide whether a tap can land on a band with no color

This is the detail that separates a careful library from a rough one, and it sits in the paletteContentScale parameter. Two scales are available, FIT, which scales the image to fit width and height, and CROP, which center crops it. The README spells out the consequence: FIT leaves bands beside the palette when the image and the canvas have different shapes, and an image can carry transparent pixels. Neither has a color to offer, so a tap there leaves the selection where it was instead of reporting the nearest edge pixel.

```kotlin
ImageColorPicker(
    modifier = Modifier.fillMaxSize(),
    controller = controller,
    paletteImageBitmap = ImageBitmap.imageResource(R.drawable.palettebar),
    paletteContentScale = PaletteContentScale.FIT, // scale the image to fit width and height.
    // paletteContentScale = PaletteContentScale.CROP, // center crop the image.
)
```

So the picker reports no color and no error in those regions. If your palette image is a PNG with transparency, or if the canvas is a different aspect ratio than the image, expect silent no-ops at the edges, and either crop the source or handle it in your own callback.

## Feeding in a gallery photo through the photo picker

The README shows how to load a user-selected image into the picker, using the modernstorage Photo Picker and a launcher for an activity result. The callback receives a list of URIs, takes the first, and decodes it differently depending on the Android version, using ImageDecoder on API 28 and above and MediaStore.Images.Media.getBitmap below that. The decoded bitmap is then handed to the controller through setPaletteImageBitmap, which is the same function used to set a palette from a drawable resource. That the library itself does not ship a gallery picker is worth noting: it gives you the bridge from a URI to a bitmap and leaves the picker UI to the host app, which keeps the dependency surface small and the choice of photo picker yours.

## Adding it: Maven coordinates, a version catalog, or a KMP source set

The artifact comes from Maven Central. For a project using a version catalog, the README shows the entries to add to libs.versions.toml.

```toml
[versions]
#...
colorpicker = "1.3.0"

[libraries]
#...
compose-colorpicker = { module = "com.github.skydoves:colorpicker-compose", version.ref = "colorpicker" }
```

For a single platform module the README gives a Gradle dependencies block with implementation("com.github.skydoves:colorpicker-compose:1.3.0"), and for Kotlin Multiplatform it adds the dependency to commonMain.dependencies inside a sourceSets block. The repository shows the expected version, 1.3.0, which matches the most recent release tag, so the two do not drift. The demo directory carries androidApp, desktopApp, shared and wasmApp, which is how the multiplatform promise is kept honest across targets.

## Which targets actually work

The README publishes a support map, and it is worth reading literally. Android, Desktop, iOSArm64 and iosSimulatorArm64, macosArm64, and js/WasmJs are all marked as supported. What that map does not say is how complete each target is, and for a library that draws palettes and handles pointer gestures, a green check is a claim about the build, not necessarily about parity of behaviour. The library does ship gesture lifecycle callbacks, which are the part most likely to differ between desktop pointer input and Android touch input. The repository layout backs up the multiplatform claim with an iosApp directory, a kotlin-js-store directory, a buildSrc directory, a spotless directory and a benchmark directory, so the build is set up for several targets rather than one. Latest release is 1.3.0 from 2026-09-16, and the last push was on 2026-10-13.

## Conclusion

colorpicker-compose fits Compose or Kotlin Multiplatform apps that need to sample a color from a photo, a palette image or a drawable, and that want the same picker code on Android, iOS, desktop and wasm. It does not fit a team that needs a native-platform color picker outside Compose, or one that expects a tap to always return a color, since a tap on a transparent pixel or on a band beside a fitted image leaves the selection unchanged. Verify first which targets your module actually needs against the support map in the README, then decide between the FIT and CROP content scales, because CROP removes the bands where the no-color behaviour appears.

## FAQ

### How do I add colorpicker-compose to an Android project?

The README gives a Gradle dependencies block with implementation("com.github.skydoves:colorpicker-compose:1.3.0") for a single platform module, or a sourceSets entry in commonMain.dependencies for Kotlin Multiplatform. Projects using a version catalog add a compose-colorpicker library entry with the version ref.

### Which platforms does colorpicker-compose support?

The README support map lists Android, Desktop, iOSArm64 and iosSimulatorArm64, macosArm64, and js/WasmJs as supported. The library requires API level 21 or higher on Android.

### What happens if I tap a transparent pixel in ImageColorPicker?

The README states that an image can carry transparent pixels and that such an area has no color to offer, so a tap there leaves the selection where it was instead of reporting the nearest edge pixel. The same applies to the bands left beside a fitted image when PaletteContentScale.FIT is used.

### How do I pick a color from a photo in the gallery?

The README shows using the modernstorage Photo Picker with rememberLauncherForActivityResult, decoding the resulting URI into an ImageBitmap and passing it to controller.setPaletteImageBitmap. The library provides the bridge from URI to bitmap rather than its own picker screen.

## Sources

- [License: Apache-2.0](https://github.com/skydoves/colorpicker-compose/blob/main/LICENSE)
- [Project website](https://skydoves.github.io/colorpicker-compose/)
- [README](https://github.com/skydoves/colorpicker-compose/blob/main/README.md)
- [Releases](https://github.com/skydoves/colorpicker-compose/releases)
- [skydoves/colorpicker-compose on GitHub](https://github.com/skydoves/colorpicker-compose)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/skydoves-colorpicker-compose
