
Select images with configurable aspect ratios, native integration, and an easy async API returning image bytes; integrates with UI layers via simple launcher registration and ViewModel support.
A Kotlin Multiplatform image selection library for Android, iOS and Desktop.
| Platform | Supported |
|---|---|
| Android | ✔️ |
| iOS | ✔️ |
| Desktop | ✔️ |
| Web | ❌️ |
See the releases section of this repository for the latest version.
To your build.gradle under commonMain.dependencies add:
implementation "com.wannaverse:imageselector:<version>"Important this library uses native code. You will need the additional dependencies depending on the targets you are building for:
Android under androidMain.dependencies: implementation("com.wannaverse:imageselector-android:")
iOS (ARM) under iosMain.dependencies: implementation("com.wannaverse:imageselector-iosarm64:")
iOS x64 under iosMain.dependencies: implementation("com.wannaverse:imageselector-iosx64:")
jvm: implementation("com.wannaverse:imageselector-jvm:")
Below is a sample code that you may use.
When setting up the image selector on Android, you will need to add the following to your MainActivity's onCreate function:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Add these to register the image selector
setImageSelectorActivity(this)
registerImageSelectorLauncher()
}Example ViewModel:
class AppViewModel : ViewModel() {
val image = mutableStateOf<ImageData?>(null)
val showLoadingState by mutableStateOf(false)
fun chooseImage() = viewModelScope.launch {
image.value = selectImage( loadingState = { showLoadingState = it } )
}
}Note:
selectImage()return a downscaled image for the current window to preventOutOfMemoryError. That's why it may take several seconds to return the image bytes. So, aloadingStatecallback is provided to show aCircularProgressIndicatorto make the UI look responsive instead of frozen during image processing.
Example Composable:
@Composable
fun App(viewModel: AppViewModel = viewModel { AppViewModel() }) {
val image = remember { viewModel.image }
val bitmap = image.value?.bytes?.toImageBitmap()
if(viewModel.showLoadingState) {
Dialog(
onDismissRequest = { /* Non-Dismissible */ }
) {
CircularProgressIndicator()
}
}
Column(modifier = Modifier
.fillMaxSize()
.safeContentPadding()
) {
Button(
modifier = Modifier.align(Alignment.CenterHorizontally),
onClick = { viewModel.chooseImage() }
) {
Text(
text = "Select Image"
)
}
bitmap?.let {
Image(
bitmap = it,
contentDescription = null
)
}
}
}You can then compress the selected image when needed:
val compressed = image.value?.compress(
ImageCompressionOptions(
quality = 88
)
)Or target a maximum size, for example 5 MB:
val underFiveMb = image.value?.compressToMaxBytes(
maxBytes = 5L * 1024L * 1024L
)Note:
maxBytesis only enforced for JPEG images. PNG is a lossless format with no quality parameter, so themaxBytesconstraint is ignored when compressing to PNG, the image will be returned at full size.
MIT LICENSE. See LICENSE for details.
Pull requests and feature requests are welcome! If you encounter any issues, feel free to open an issue.
A Kotlin Multiplatform image selection library for Android, iOS and Desktop.
| Platform | Supported |
|---|---|
| Android | ✔️ |
| iOS | ✔️ |
| Desktop | ✔️ |
| Web | ❌️ |
See the releases section of this repository for the latest version.
To your build.gradle under commonMain.dependencies add:
implementation "com.wannaverse:imageselector:<version>"Important this library uses native code. You will need the additional dependencies depending on the targets you are building for:
Android under androidMain.dependencies: implementation("com.wannaverse:imageselector-android:")
iOS (ARM) under iosMain.dependencies: implementation("com.wannaverse:imageselector-iosarm64:")
iOS x64 under iosMain.dependencies: implementation("com.wannaverse:imageselector-iosx64:")
jvm: implementation("com.wannaverse:imageselector-jvm:")
Below is a sample code that you may use.
When setting up the image selector on Android, you will need to add the following to your MainActivity's onCreate function:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Add these to register the image selector
setImageSelectorActivity(this)
registerImageSelectorLauncher()
}Example ViewModel:
class AppViewModel : ViewModel() {
val image = mutableStateOf<ImageData?>(null)
val showLoadingState by mutableStateOf(false)
fun chooseImage() = viewModelScope.launch {
image.value = selectImage( loadingState = { showLoadingState = it } )
}
}Note:
selectImage()return a downscaled image for the current window to preventOutOfMemoryError. That's why it may take several seconds to return the image bytes. So, aloadingStatecallback is provided to show aCircularProgressIndicatorto make the UI look responsive instead of frozen during image processing.
Example Composable:
@Composable
fun App(viewModel: AppViewModel = viewModel { AppViewModel() }) {
val image = remember { viewModel.image }
val bitmap = image.value?.bytes?.toImageBitmap()
if(viewModel.showLoadingState) {
Dialog(
onDismissRequest = { /* Non-Dismissible */ }
) {
CircularProgressIndicator()
}
}
Column(modifier = Modifier
.fillMaxSize()
.safeContentPadding()
) {
Button(
modifier = Modifier.align(Alignment.CenterHorizontally),
onClick = { viewModel.chooseImage() }
) {
Text(
text = "Select Image"
)
}
bitmap?.let {
Image(
bitmap = it,
contentDescription = null
)
}
}
}You can then compress the selected image when needed:
val compressed = image.value?.compress(
ImageCompressionOptions(
quality = 88
)
)Or target a maximum size, for example 5 MB:
val underFiveMb = image.value?.compressToMaxBytes(
maxBytes = 5L * 1024L * 1024L
)Note:
maxBytesis only enforced for JPEG images. PNG is a lossless format with no quality parameter, so themaxBytesconstraint is ignored when compressing to PNG, the image will be returned at full size.
MIT LICENSE. See LICENSE for details.
Pull requests and feature requests are welcome! If you encounter any issues, feel free to open an issue.