SkillAgentSearch skills...

ImagePickerKMP

ImagePickerKMP – Cross‑platform Image Picker & Camera Library (Android & iOS) built with Kotlin Multiplatform + Compose Multiplatform.

Install / Use

/learn @ismoy/ImagePickerKMP

README

ImagePickerKMP

Cross-platform Image Picker & Camera Library for Kotlin Multiplatform

Easily capture or select images on Android, iOS, Desktop, and Web — all with a single API.
Built with Compose Multiplatform, designed for simplicity, performance, and flexibility.

<img referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=b9cde436-d518-45b7-9a4a-7b4e084aeffa" /> <p align="center"> <img src="https://raw.githubusercontent.com/ismoy/CameraKMP/main/thumnailImagePickerKMP.png" alt="ImagePickerKMP Banner" width="100%"> </p> <p align="center"> <a href="https://github.com/ismoy/ImagePickerKMP/actions"><img src="https://github.com/ismoy/ImagePickerKMP/workflows/CI/badge.svg" alt="CI"></a> <a href="https://codecov.io/gh/ismoy/ImagePickerKMP"><img src="https://codecov.io/gh/ismoy/ImagePickerKMP/branch/main/graph/badge.svg" alt="Code Coverage"></a> <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License"></a> <a href="https://kotlinlang.org"><img src="https://img.shields.io/badge/Kotlin-2.3.20-blue.svg" alt="Kotlin"></a> <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section --> <a href="#contributors"><img src="https://img.shields.io/github/all-contributors/ismoy/ImagePickerKMP?color=ee8449&style=flat-square" alt="All Contributors"></a> <!-- ALL-CONTRIBUTORS-BADGE:END --> </p> <p align="center"> <a href="https://search.maven.org/artifact/io.github.ismoy/imagepickerkmp"><img src="https://img.shields.io/maven-central/v/io.github.ismoy/imagepickerkmp.svg?label=Maven%20Central" alt="Maven Central"></a> <a href="https://www.npmjs.com/package/imagepickerkmp"><img src="https://img.shields.io/npm/v/imagepickerkmp.svg?label=NPM" alt="NPM Version"></a> <a href="https://www.npmjs.com/package/imagepickerkmp"><img src="https://img.shields.io/npm/dt/imagepickerkmp.svg" alt="NPM Downloads"></a> <a href="https://github.com/ismoy/ImagePickerKMP/releases"><img src="https://img.shields.io/github/v/release/ismoy/ImagePickerKMP?label=GitHub%20Release" alt="GitHub Release"></a> <a href="https://github.com/ismoy/ImagePickerKMP/stargazers"><img src="https://img.shields.io/github/stars/ismoy/ImagePickerKMP?style=social" alt="GitHub Repo stars"></a> <a href="https://github.com/ismoy/ImagePickerKMP/commits/main"><img src="https://img.shields.io/github/last-commit/ismoy/ImagePickerKMP" alt="GitHub last commit"></a> </p> <p align="center"> <img src="https://img.shields.io/badge/Compose%20Multiplatform-green" alt="Compose Multiplatform"> <img src="https://img.shields.io/badge/Platform-Android-green" alt="Android"> <img src="https://img.shields.io/badge/Platform-iOS-blue" alt="iOS"> <img src="https://img.shields.io/badge/Platform-Desktop-orange" alt="Desktop"> <img src="https://img.shields.io/badge/Platform-JS-yellow" alt="JavaScript"> <img src="https://img.shields.io/badge/Platform-WASM-purple" alt="WebAssembly"> <a href="https://github.com/ismoy/ImagePickerKMP/actions/workflows/detekt.yml"> <img src="https://github.com/ismoy/ImagePickerKMP/actions/workflows/detekt.yml/badge.svg?branch=main" alt="Detekt"></a> </p>
<p align="center"> <a href="https://imagepickerkmp.dev/"> <img src="https://img.shields.io/badge/%20Full%20Documentation-Visit%20Docs%20Site-0ea5e9?style=for-the-badge&logoColor=white" alt="Documentation Site"> </a> &nbsp; <a href="https://github.com/sponsors/ismoy"> <img src="https://img.shields.io/badge/Sponsor-%E2%9D%A4-red?style=for-the-badge&logo=github" alt="Sponsor"> </a> </p>

ImagePickerKMP saves you 2 weeks of native Android/iOS/Web integration work.
It's free and open source. If your app or company benefits from it, consider sponsoring to keep it maintained and updated with every new KMP/Compose release.
→ Become a sponsor


Example

Complete Example App

ImagePickerKMP-Example →

Full-featured sample application showcasing:

  • All library features and configurations

Quick Start

⚠️ Requirements

| Requirement | Minimum version | |---|---| | Kotlin | 2.3.20 (breaking change — see CHANGELOG) | | Compose Multiplatform | 1.10.3 | | Ktor | 3.4.1 | | Android minSdk | 24 | | Android compileSdk | 36 |

Note: This library is compiled with Kotlin 2.3.20. Projects using Kotlin < 2.3.x will get an ABI incompatibility error at compile time. If you need Kotlin 2.1.x support, use a previous version of this library.

Installation

Kotlin Multiplatform:

dependencies {
    implementation("io.github.ismoy:imagepickerkmp:1.0.35-alpha1")
}

React/JavaScript:

npm install imagepickerkmp

New — rememberImagePickerKMP (recommended)

The modern, idiomatic Compose API. A single state holder — no manual booleans, no Render() call needed.

@Composable
fun basicUsageScreen() {
    val picker = rememberImagePickerKMP(
        config = ImagePickerKMPConfig(
            galleryConfig = GalleryConfig(
                allowMultiple = true,
                selectionLimit = 20
            )
        )
    )
    val result = picker.result

    Scaffold(
        modifier = Modifier
            .fillMaxSize(),
        topBar = {
            TopAppBar(
                title = { Text("Basic Usage") },
                navigationIcon = {
                    IconButton(onClick = {}) {
                        Icon(
                            imageVector = Icons.AutoMirrored.Filled.ArrowBack,
                            contentDescription = "Go back"
                        )
                    }
                }
            )
        },
        bottomBar = {
            BottomAppBar {
                Row(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(horizontal = 16.dp),
                    horizontalArrangement = Arrangement.spacedBy(8.dp)
                ) {
                    Button(
                        onClick = { picker.launchCamera() },
                        modifier = Modifier.weight(1f)
                    ) {
                        Text("Camera")
                    }
                    Button(
                        onClick = { picker.launchGallery() },
                        modifier = Modifier.weight(1f)
                    ) {
                        Text("Gallery")
                    }
                }
            }
        }
    ){scaffoldPadding->
        Column(
            modifier = Modifier
                .padding(scaffoldPadding)
                .fillMaxSize()
        ) {
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .weight(1f),
                contentAlignment = Alignment.Center
            ) {
                when (result) {

                    is ImagePickerResult.Loading -> {
                        Column(
                            horizontalAlignment = Alignment.CenterHorizontally,
                            modifier = Modifier.padding(16.dp)
                        ) {
                            CircularProgressIndicator()
                            Text(
                                text = "Loading...",
                                color = Color.Gray,
                                modifier = Modifier.padding(top = 12.dp)
                            )
                        }
                    }

                    is ImagePickerResult.Success -> {
                        // Result here
                    }

                    is ImagePickerResult.Error -> {
                        Text(
                            text = "Error: ${result.exception.message}",
                            color = Color.Red,
                            modifier = Modifier.padding(16.dp)
                        )
                    }

                    is ImagePickerResult.Dismissed -> {
                        Text("Selection cancelled", color = Color.Gray)
                    }

                    is ImagePickerResult.Idle -> {
                        Text("Press a button to get started", color = Color.Gray)
                    }
                }
            }
        }
    }
}

Per-launch overrides:

// Override gallery options for a single launch
picker.launchGallery(
    allowMultiple = true,
    selectionLimit = 5,
    mimeTypes = listOf(MimeType.IMAGE_JPEG),
    includeExif = true
)

// Override camera options for a single launch
picker.launchCamera(
    cameraCaptureConfig = CameraCaptureConfig(compressionLevel = CompressionLevel.HIGH),
    enableCrop = false
)

New API vs Legacy API — Migration Guide

TL;DR: Use rememberImagePickerKMP for all new code. The legacy ImagePickerLauncher / GalleryPickerLauncher are deprecated and will be removed in a future major release.

Side-by-side comparison

| | Legacy API (v1) — Deprecated | New API (v2) — Recommended | |---|---|---| | Camera | ImagePickerLauncher(config = ...) | picker.launchCamera() | | Gallery | GalleryPickerLauncher(...) | picker.launchGallery() | | Result handling | Callbacks (onPhotoCaptured, onDismiss, onError) | Reactive when (picker.result) | | State management | Manual showCamera, showGallery booleans | Automatic via ImagePickerKMPState | | Per-launch config | Not supported | Override any param on each launch*() call | | Reset | Call onDismiss callback | picker.reset() | | Configuration | ImagePickerConfig + GalleryPickerConfig | ImagePickerKMPConfig (unified) |

Migration table

| Legacy pattern | New API equivalent | |---|---| | showCamera = true | picker.launchCamera() | | showGallery = true | picker.launchGallery() | | onPhotoCaptured = { result -> ... } | is ImagePickerResult.Success -> result.photos | | `onDismis

Related Skills

View on GitHub
GitHub Stars168
CategoryDevelopment
Updated1d ago
Forks16

Languages

Kotlin

Security Score

100/100

Audited on Apr 8, 2026

No findings